首页 MFC 其他 MDI中的快捷键的实现
MDI中的快捷键的实现 PDF 打印 E-mail
用户评价: / 1
好 
MFC - 其他
作者:Administrator   
周日, 20 7月 2008 09:34

在使用windows程序的时候,我们用快捷键来使操作更加方便。比如在一个MDI程序中,不管当前输入焦点(接收键盘消息)在哪里,在view中也好,在edit中也好,按下快捷键,对应的消息响应总是会被调用,给我们的感觉,好像accelerator keys和当前focus没有关系。

实际上,在msdn中这样解释:

The TranslateAccelerator function processes accelerator keys for menu commands. The function translates a WM_KEYDOWN or WM_SYSKEYDOWN message to a WM_COMMAND or WM_SYSCOMMAND message

也就是说它是从WM_KEYDOWN开始的,接收按键消息的,必然是当前有输入focus的窗口才对,但是为什么在MDI中,我们添加的快捷键和focus看上去没有关系呢?

实际上,是MFC进行了操作,使得accelerator key与当前focus没有关系,只要你在MDI的main frame中导入快捷键即可。MFC是怎么实现的呢?

MFC在pump message的时候,会调用PreTranslateMessage

//in BOOL CWinThread::PumpMessage() in THRDCORE.CPP

if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
    {
        ::TranslateMessage(&m_msgCur);
        ::DispatchMessage(&m_msgCur);
    }

而PreTranslateMessage会调用CWnd::WalkPreTranslateTree(),一直上溯到main window,也就是mdi的main frame。

if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
    return TRUE;

而CWnd::WalkPreTranslateTree会从当前得到消息的focus窗口,一直找parent,找到在某个parent中快捷键消息被响应为止。

BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
    ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
    ASSERT(pMsg != NULL);

    // walk from the target window up to the hWndStop window checking
    //  if any window wants to translate this message

    for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
    {
        CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
        if (pWnd != NULL)
        {
            // target window is a C++ window
            if (pWnd->PreTranslateMessage(pMsg))
                return TRUE; // trapped by target window (eg: accelerators)
        }

        // got to hWndStop window without interest
        if (hWnd == hWndStop)
            break;
    }
    return FALSE;       // no special processing
}

这样,在MDI中,把快捷键响应汇聚到一个地方,只需要在main frame中响应快捷键就可以了,不用在每个view啊,edit中都加入代码。

到这里,MFC实现了收集快捷键消息,在一个地方查询快捷键表,转换。

然后还有另外一个问题,汇集到一个地方转换快捷键了,怎么最后响应消息调用的还是对应的edit或者view的消息响应函数呢?MFC把快捷键都转换成WM_COMMAND后,都送给main frame窗口,在CFrameWnd::OnCmdMsg()又向下查询,送给真正准备响应消息的view(然后给doc)或者其他窗口,去看看CFrameWnd::OnCmdMsg()的代码吧,别的文章(1,2)也有讲的 :-)