C++ 将MFC CListBox控件升级为ON_WM_RBUTTONDOWN,以便对话框可以直接处理消息

C++ 将MFC CListBox控件升级为ON_WM_RBUTTONDOWN,以便对话框可以直接处理消息,c++,mfc,clistbox,C++,Mfc,Clistbox,我想知道为CListBox控件提供的消息控制器集有多有限。我已经在包含此控件的CDialog的消息映射中使用了ON\u LBN\u SELCHANGE 我还想在Buttondown上使用,因此我派生了一个类CMyListBox:public CListBox,因此现在我可以在类内映射该消息,但我想以与SELCHANGE上的相同的方式将其映射到对话框 我的问题是,是否可以将该消息重新发送到父对话框,以便我可以从CDialog消息映射处理它,以及这样做的最佳方式是什么(发送消息、发布消息还是有更好的

我想知道为
CListBox
控件提供的消息控制器集有多有限。我已经在包含此控件的
CDialog
的消息映射中使用了
ON\u LBN\u SELCHANGE

我还想在Buttondown上使用
,因此我派生了一个
类CMyListBox:public CListBox
,因此现在我可以在类内映射该消息,但我想以与SELCHANGE
上的
相同的方式将其映射到对话框


我的问题是,是否可以将该消息重新发送到父对话框,以便我可以从
CDialog
消息映射处理它,以及这样做的最佳方式是什么(发送消息、发布消息还是有更好的通知机制)?

您可以将控件设置为向父对话框发送
WM\u PARENTNOTIFY
消息(默认情况下不会),并向对话框类添加对的重写。基本程序如下所述

首先,需要从列表框控件中删除
WS\u EX\u NOPARENTNOTIFY
样式,以便它将所需的消息发送给其父控件。有几种方法可以做到这一点,但一种非常简单的方法是修改
OnInitDialog
覆盖中的“ex样式”,如下所示:

BOOL MyDialog::OnInitDialog(void)
{
CDialog::OnInitDIalog();//调用基类
//...
//您需要的其他代码
//
CWnd*pList=GetDlgItem(IDC_MYLISTBOX);//使用列表框的资源ID
LONG_PTR exstyle=GetWindowLongPtr(pList->m_hWnd,GWL_exstyle);
//删除WS_EX_NOPARENTNOTIFY位。。。
exstyle&=~WS_EX_NOPARENTNOTIFY;
SetWindowLongPtr(pList->m_hWnd,GWL_EXSTYLE,EXSTYLE);//设置新样式
//...
return TRUE;//假设没有显式设置焦点
}
然后,您需要将\u WM\u PARENTNOTIFY上的
添加到对话框的消息映射中:

BEGIN\u MESSAGE\u MAP(MyDialog,CDDialog)
//...
关于\u WM\u PARENTNOTIFY()
结束消息映射()
最后,拦截通知的处理程序:

void MyDialog::OnParentNotify(UINT消息,LPARAM LPARAM)
{
CDialog::OnParentNotify(message,lParam);//为MFC调用基类总是最好的!
如果(消息==WM_RBUTTONDOWN){
//在这里,我们可以处理右键点击!
//lParam将是光标位置(LOWORD中的x和HIWORD中的y)
//注意:请参阅下面提到的注意事项!
}
}

这种方法的一个(潜在的麻烦)问题是(正如您可能已经注意到的)没有向处理函数传递通知来自哪个控件的信息。如果对话框中只有一个控件启用了此行为,那么就可以了;否则,您将不得不做一些技巧(使用给定的光标位置和控件的窗口矩形)来确定哪个控件发送了消息。

我想我也会向您展示这种方法,作为一种替代方法,它将节省您派生自己的
CListBox
类的需要

  • 选择对话类
  • 在属性窗格中选择消息图标
  • 在列表中找到并通过下拉菜单添加处理程序
  • 此处理程序的说明如下:

    通知窗口用户希望显示上下文菜单。用户可能已在窗口中单击鼠标右键(单击鼠标右键),按下Shift+F10或按下某些键盘上可用的应用程序键(关联菜单键)

    wParam
    -用户右键单击鼠标的窗口句柄。这可以是接收消息的窗口的子窗口。有关处理此消息的更多信息,请参阅备注部分

    您需要取消注释要在生成的处理程序中使用的参数。例如:

    void CMFCApplication4Dlg::OnContextMenu(CWnd* pWnd, CPoint /*point*/)
    {
        if (pWnd->GetSafeHwnd() == m_lbList.GetSafeHwnd())
        {
            AfxMessageBox(_T("User right-clicked on the listbox control"));
        }
    }
    
    结果:

    当然,像以前那样派生自己的类、处理鼠标按钮和使用notify系统并没有错。我并不是说这种方法更好。我只是将其显示为在对话框中检测控件右键单击的替代方法


    注:
    关于使用这种方法,这里还有其他的例子,但我发现的那些没有显示屏幕截图。

    可能是使用
    WM\u PARENTNOTIFY
    as的一个例子?@Adrian Mole:可能是这样,请您将您的评论更新为正式回复,以便人们可以投票?在那里,您可以解释如何使用您的提案:如何将
    WM\u PARENTNOTIFY
    发送到CDialog?如何打包控制器的arguncontent来生成消息?您不能只使用contextmenu处理程序并测试父处理程序吗?未测试。请参阅:这是最简单的。通过测试针对列表框传递的窗口来检测右键单击。在对话框中完成所有操作。@Andrew Truckle:谢谢,您的解决方案也是有效的,我已经检查过了,对话框消息映射上的“WM_CONTEXTMENU”在这个对话框中运行良好case@Pablo我对上述方法做了一个简短的测试,似乎光标位置是根据父对话框的客户机坐标发送的。这使得使用
    GetWindowRect()
    函数获取活动控件变得稍微容易一些。好吧,这与其他一些控件一样。顺便说一句,这使得在CListBox中点击哪个项目变得更加困难,但这并不是旧的good
    ScreenToClient
    可以轻松解决的问题。祝贺您提到了
    WM_CONTEXTMENU
    。直接处理右键单击消息会绕过许多标准Windows行为。感谢您的解决方案和解释。您已经声明cristal明确了您的建议,并提供了一些截图,提供了极大的帮助。干得好!