关于MFC 在一个对话框内有两个控件,在其中一个控件内点击拖动到另一控件松开,然后交换控件的位置怎么实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于MFC 在一个对话框内有两个控件,在其中一个控件内点击拖动到另一控件松开,然后交换控件的位置怎么实现?相关的知识,希望对你有一定的参考价值。

关于MFC 在一个对话框内有两个控件,鼠标在其中一个控件内点击拖动到另一控件松开,然后交换控件的位置怎么实现?我的思路是用hook,因为对话框LButtonDown事件控件上无效,但是不知道怎么判断截获鼠标点击的位置是在控件范围内,请详细回答,谢谢,可以多加分。

我已经实现了你说的东东,可以baidu hi我,我发工程给你。

我用的button按钮控件,方法是:
1、重载CButton类,写了个自己的CMyButton类,在这里实现按钮拖动,和拖动完成后给父窗口发完成消息
2、当主窗口收到按钮发的拖动完成消息后,判断两个按钮是否相交,如果相交,则交换两个按钮位置

当然,其它控件也可以用类似方法实现,有什么问题Hi我就行追问

你能不能发到我邮箱上去zhaoqi0128@163.com,如果可以解决问题就把分数给你

追答

已发送

追问

要实现的效果是差不多,不过有个很重要的区别是我的控件不是按钮,我用hook窗口也截取不到鼠标事件,只能在控件以外的范围hook到,现在在考虑hook整个屏幕,判断鼠标事件,不过具体还没实现,有什么其他好的方法么?感觉我的控件是一个很特殊的地方,不是系统自带的。

追答

我发了封邮件给你,查收下

追问

我觉的你的方法应该能解决问题,你能不能把你后面做的那个完整一些发给我一下,我不知道怎么用

参考技术A MFC不清楚..不过你可以做一个粘合层来处理两个控件的消息传递, 以及消息的处理等.

你可以在粘合层开一个线程, 定时取GetKeyState(VK_LBUTTON), 可以通过两个控件的初始位置和GetCursorPos共同确定新的窗口位置, 也可以提供对应的setPos/getPos来手动指定..
当你那个线程检测到两个控件的位置rect有相交时, 就可以MoveWindow来实现调换位置了(只要记录下连个控件的初始位置就好, 这两个rect都可以通过提供set/get方法来手动指定给粘合层)

当然..最简单的方法就是你如果能直接处理WndProc是最好的...有一个ws的方法可以取到.
就是GetWindowLong取到现有的WndProc, 然后SetWindowLong设置你自己的WndProc, 在自己的WndProc里面判断是否是你那两个控件产生了移动消息..不是的话就调用老的WndProc, 是的话就直接return就行了..不过这样就失去了用MFC的意义..是WIN32编程的方法 = =

至于hook..也是可以的..写个dll而已..

嘛..最好还是直接处理MouseMove消息比较好..
参考技术B 楼主,你也真是的,人家已经发给你样例了,你又说你的控件不是 BUTTON ,那你的控件究竟是什么呢?如果是任何控件,那你也可以按照人家给你 BUTTON 的样例,进行改进就可以了。哪有拿过来就要能直接用的事情?

你说别人在较真,我看楼主倒是在较真。都提醒过你了,别用 HOOK ,可你还是往 HOOK 方面去考虑。像这种简单的功能,居然要借助 HOOK ,实在有点说不过去。

我觉得 niuxiaojia45 的实现方式和我想的差不多。当确定了哪个种类的控件需要被拖拽,首先子类化该控件,然后当该控件收到鼠标被按下的消息后,该控件通过 SendMessage 发送自定义消息给父窗口,通知其父窗口,该控件要被拖动。至于拖动的事情,还是让父窗口来决定。理由是:控件是占用父窗口的客户区的。
说白了,控件是房子的承租人,父窗口是大楼的房东,承租人要搬到该楼的其它房间去,应该是承租人通知大楼房东,大楼房东来决定承租人是否能搬到其它房间里去。因为承租人是不知道其它房间的使用情况的,只有房东最清楚。
因此,控件要移动,控件不能自己自说自话的移动,应该通知父窗口。由父窗口来移动控件,因为父窗口还能确定客户区中其它控件的位置。简而言之,这是一个控件群的布局问题,布局由父窗口来负责。 当然,现在的控件布局,也允许控件自身来参与布局决策,而不是完全由父窗口来全权包办的。例如 WPF 就是父窗口与控件协调参与布局的一种机制。因此,是子控件自己移动,还是父窗口来统一管理,看实际需要。一般都是父窗口来打理。

另外,鼠标拖放也是一种实现方式,不过该方式需要和 COM 交互,实现的复杂度较高。初学者很难实现。事实上,鼠标拖拽就是控件发送消息,父窗口来管理控件布局的一种模式。作为 IDropSource 源的控件在鼠标拖动时,通知父窗口,拖动的鼠标坐标等通过 IDataObject 传递给父窗口,当然 IDataObject 能传递的内容可以远远多于鼠标坐标这种简单的信息。 作为 IDropTarget 的父窗口,来决定具体的“放”操作。
参考技术C 按钮自己画,处理对话框消息。效果远好于你用hook。你要会简单的ps比较好。现在很多应用程序的控件都是自己画的追问

我的控件不是按钮啊,我发现窗口hook也不行,悲剧,还是只能在控件以外的窗口hook到鼠标信息,有什么其他好的方法么?现在在考虑直接hook整个屏幕在选取坐标

追答

不用任何控件,都是自己画。hook,hook,貌似你hook很牛X?那希望你再接再厉,用hook去实现吧

追问

我在找办法。。你说办法就好了,初学嘛,你较什么真啊。。

参考技术D vc支持拖放操作啊,需要从一个类中派生下,具体记不清楚了,自己查吧。hook是效率最低最不可取的办法。
实在不行 setcapture来捕捉鼠标位置 再做击中测试也要好得多。
第5个回答  2011-04-26 你要空间的LButtonDown干啥,直接获取对话框的LButonDown事件,判断如果此时point在第一个控件的rect里面,那么开始移动此控件位置,不断InValidate 不断setwindowpos 或者movewindow,直到 判断点到了另一个控件的rect里面时,两者就交换位置。追问

对控件点击左键无法获取LButtonDown事件,还有交换控件位置怎么实现?

追答

你要控件的LButtonDown干啥,直接获取对话框的LButonDown事件

追问

对话框的LButtonDown在控件范围内的点击是不产生事件,控件在对话框之上。

追答

谁说的,你试过没,对话框上所有控件都是对话框的子类,对话框所有子类的消息都是由对话框的消息循环负责的。

追问

我试过,你确定是这样么?我在对话框LButtonDown事件设置MessageBox,在控件上点击无效,其他范围才弹出对话框。你可以先回答一下 交换控件位置怎么实现,希望尽量具体点,我现在一步一步来,然后实现hook截获鼠标点击拖动

追答

你这样,先获得控件的 ClientRect,然后判断鼠标点 point 是否在ClientRect里面,这样试试

追问

hook我已经有些思路了,现在在交换两个控件位置出现问题,位置交换都和我想的不一样,乱跳.我是想这样实现, CRect1 CRect2获取控件1和2相对对话框客户区的位置,然后交换值,然后用MoveWindow重新设置位置.

在执行自定义验证之前,MFC初始化日期时间选择器控件

我有一个带有两个日期时间控件的对话框,其格式设置为time。一个表示开始时间,另一个表示结束时间。

其中一个要求是开始时间不能超过结束时间,结束时间不能早于开始时间。

因此,我通过SetTime()函数提前一小时将结束时间初始化为当前时间。

我的问题是我正在初始化OnInitDialog()方法中的两个控件,但是DoDataExchange()OnInitDialog()函数之前运行,因此开始时间和结束时间完全相同,这导致我的验证失败并且对话框没有被创建。日期的检查是在我改编自here的自定义验证器中完成的

如何才能首先初始化日期时间控件?或者我可能没有正确地接近这个或者是否有我遗漏的东西?

OnInitDialog()

BOOL CNewManualEntryDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_dtStartTime.SetRange(&GetTodayTimeMin(), &GetTodayTimeMax());
    m_dtEndTime.SetRange(&GetTodayTimeMin(), &GetTodayTimeMax());

    m_dtEndTime.SetTime(&SetEndTimeOneHourAhead());

    return TRUE;
}

上面的函数只返回一个CTime对象。作为参考,验证器如下所示:

void CNewManualEntryDlg::TimePickerValidation(CDataExchange* pDX)
{
    CTime startTime;
    CTime endTime;
    m_dtStartTime.GetTime(startTime);
    m_dtEndTime.GetTime(endTime);

    BOOL isStartTimeBehindEndTime = startTime > endTime;
    CString errorMsg;
    if (!isStartTimeBehindEndTime)
    {
        errorMsg += "Error - Start time cannot be ahead of end time
";
    }
    if (!errorMsg.IsEmpty())
    {
        ::AfxMessageBox(errorMsg);
        pDX->Fail();
        return;
    }

}

而我只是在DoDataExchange()中称它为:

void CNewManualEntryDlg::DoDataExchange(CDataExchange* pDX)
{
   CDialogEx::DoDataExchange(pDX);

   DDX_Control(pDX, IDDT_STARTTIMEPICKER, m_dtStartTime);
   DDX_Control(pDX, IDDT_ENDTIMEPICKER, m_dtEndTime);

   TimePickerValidation(pDX);
}
答案

你总是在做验证。始终意味着,在将数据加载到对话框中以及提交数据时,您正在执行验证。

DoDataExchange()被称为两种方式。您可以确定pDX->m_bSaveAndValidate以检查您是否处于保存阶段。

if (pDX->m_bSaveAndValidate)
   TimePickerValidation(pDX);

以上是关于关于MFC 在一个对话框内有两个控件,在其中一个控件内点击拖动到另一控件松开,然后交换控件的位置怎么实现?的主要内容,如果未能解决你的问题,请参考以下文章

关于mfc 对话框 DATETIMEPICKER控件的使用

关于MFC中Slider(滑动)控件的使用

关于MFC中Slider(滑动)控件的使用

在执行自定义验证之前,MFC初始化日期时间选择器控件

MFC关于Radio Button控件的问题 高分悬赏!!敬请指点

关于VisualStudio2005中MFC通用控件的外观和使用Unicode工程的关系