MFC 重定向/捕获 MESSAGE_MAP |预翻译消息?

Posted

技术标签:

【中文标题】MFC 重定向/捕获 MESSAGE_MAP |预翻译消息?【英文标题】:MFC redirect/catching MESSAGE_MAP | PreTranslateMessage? 【发布时间】:2015-11-20 11:36:00 【问题描述】:

我在使用 MESSAGE_MAP 和/或 PreTranslateMessage 时遇到问题。这可能是设计问题,但我不确定。主要问题是未调用 MESSAGE_MAP 代码并且不确定如何通过 PreTranslateMessage 执行相同操作。即如下:

    //MyCDialogEx : public CDialogEx
    class MyCDialogEx::Init()
    
        CFlatSplitterWnd m_cSplitter; //http://www.codersource.net/2010/01/29/mfc-splitter-window/
        m_pFrame = new CFlatFrameWnd;
        m_pFrame->Create(strMyClass, L"", WS_CHILD, rect, this);
        m_pFrame->ShowWindow(SW_SHOW);
        m_cSplitter.CreateStatic(m_pFrame, 1, 2);

        m_cSplitter.ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_NOSIZE | SWP_NOACTIVATE);
        m_cSplitter.CreateView(0, 0, RUNTIME_CLASS(CHolderView), CSize(100, 100), &ccc);

        CHolderView* pView = (CHolderView*)m_cSplitter.GetPane(0, 0);
        ASSERT_VALID(pView);
        pView->setWnd(&m_TreeCtrl);
        pView->setOwner(this, IDC_TREECTRL);

        const DWORD dwStyle = LBS_NOTIFY | WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES
         | TVS_LINESATROOT | TVS_CHECKBOXES | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP;
        m_TreeCtrl.Create(dwStyle, CRect(0, 0, 1, 1), pView, IDC_TREECTRL);
    

    BEGIN_MESSAGE_MAP(MyCDialogEx, CDialogEx)
        ON_NOTIFY_REFLECT(WM_ONMYCLICK, OnClickTreectrl) //this & following not called
        ON_NOTIFY(NM_CLICK, IDC_TREECTRL, OnClickTreectrl)
        ON_NOTIFY(TVN_ITEMCHANGED, IDC_TREECTRL, OnItemchangedTreectrl)
        ON_NOTIFY(TVN_SELCHANGED, IDC_TREECTRL, OnSelchangedTreectrl)
        ON_NOTIFY(TVN_KEYDOWN, IDC_TREECTRL, OnKeydownTreectrl)
    END_MESSAGE_MAP()

    BOOL MyCDialogEx::PreTranslateMessage(MSG* pMsg)
    
        if (GetFocus() && GetFocus()->GetDlgCtrlID() == IDC_TREECTRL)
        
            //what/how goes in here to catch NM_CLICK, TVN_ITEMCHANGED etc??

            if (pMsg->message == WM_LBUTTONDOWN)
            
                switch (LOWORD(pMsg->wParam))
                
                case NM_CLICK:
                    break;
                
            
            if (pMsg->message == WM_KEYDOWN)
                TRACE(L"WM_KEYDOWN\n");

            if (pMsg->message == WM_KEYUP)
                TRACE(L"WM_KEYUP\n");
        
        return MyCDialogEx::PreTranslateMessage(pMsg);
    
    void MyCDialogEx::OnClickTreectrl(NMHDR *pNMHDR, LRESULT *pResult) //not called
    
        TRACE(L"tree click\n");
        *pResult = 0;
    

如果我将这些放在 CHolderView 类 MESSAGE_MAP 中,MESSAGE_MAP 可以工作,但我宁愿不这样做,因为它只是一个容器类并且可能会在我的项目的其他地方使用。

我真正想做的是使用 MESSAGE_MAP 通过 PreTranslateMessage 最小化编码(如果可以重定向到 MESSAGE_MAP,如何?)。如果我必须求助于 PreTranslateMessage 或其他,那么我该如何使用它以便我可以捕获相关的 NM_CLICK、TVN_ITEMCHANGED 进行树控制等。

谢谢。

编辑:哦,以下内容没有帮助,不相关或没有充分解释:

How to get Click Event of Treeview(CTreeCtrl) in MFC created at runtime? How to redirect MFC messages to another object? How can identify Mouse Click event in PreTranslateMessage?

【问题讨论】:

【参考方案1】:

问题是树视图会将其所有通知发送到父窗口。而父窗口是CHolderWindow。

消息不像 WM_COMMAND 消息那样被路由。因此 WM_COMMAND 消息的处理程序可以驻留在通知路径中的任何位置。

但常规窗口控制通知总是在窗口的直接父级中处理。在 MFC 中,您可以将此类通知重定向到子窗口控件本身。使用 ON_..._REFLECT。

一个技巧可以是:将一个指向窗口的指针设置为持有者窗口,该窗口应该接收所有消息。比接受持有者窗口中的所有 WM_COMMAND 和所有 WM_NOTIFY 消息并将它们重新发送到新窗口。

PreTranslateMessage 是另一回事。目标窗口总是首先收到一个调用。在 PreTranslateMessage 调用链中的某个人返回 TRUE 之前,所有父母都会有机会。

【讨论】:

“一个技巧可以......”你能详细说明一下吗? CHolderWindow 有一个指向子窗口的指针,但调用 m_pDlgOwner->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);在它的 PreTranslateMessage 中没有调用 childs message_map 并且在 CHolderWindow 中使用反射没有被调用:/。即ON_NOTIFY_REFLECT(NM_CLICK, OnClickCtrl) 我的意思是cou可以除了WM_COMMAND/WM_NOITY消息在持有者Windows中,然后重新发送给孩子。这对 PreTranslateMessage 永远不起作用,如果之前未处理过消息,父类将有机会处理 PreTranslateMessage!所以没有理由“用 PreTranslateMessage 重新发送一些东西”

以上是关于MFC 重定向/捕获 MESSAGE_MAP |预翻译消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MFC 中重定向 TRACE 语句以减少来自 AfxDumpStack() 的数据流?

Laravel - 以 .php 结尾的重定向捕获/重定向 URL

在 EasyAdmin 3 中使用预填充值重定向到新操作

Sentry 捕获错误时重定向到新页面

可以通过 shell 重定向捕获彩色输出吗? [复制]

如何在 webview 中捕获网站重定向