对于加速键我有点乱,比如我创建一个加速键(Ctrl+Z),他是用来加速菜单项"aaa"的,那么我在视图类中又定义了一个CEdit m_edit;的控件.我要求当焦点落在Edit里是,也可以用加速键(Ctrl+Z)来处理撤销这个操作,1.现在要怎么做??
2.一个加速键可不可以对应多个不同的对象(比如既用来加速菜单项又用来加速其他东西)???如果可以的话,不会乱掉吗??
我也不知道要怎么说了.

解决方案 »

  1.   

    你可以重载主窗口的PreTranslateMessage函数,加入如下代码:
    if (pMsg->message == WM_KEYDOWN)
    {
    if (pMsg->hwnd == Edit句柄 && (GetAsyncKeyState(VK_CONTROL) & 0x8000) && pMsg->wParam == 'Z')
    {
    TranslateMessage(pMsg);
    return TRUE;
    }
    }
    return 基类::PreTranslateMessage(pMsg);
      

  2.   

    窗口程序是通过消息循环来响应消息的,通常的流程是GetMessage、TranslateAccelerator、TranslateMessage、DispatchMessage,TranslateAccelerator就是匹配加速键,在MFC中,PreTranslateMessage函数是在TranslateAccelerator之前被调用的,上述做法就是判断一下,如果当前消息是发给Edit的Ctrl+Z,就跳过TranslateAccelerator直接TranslateMessage。
      

  3.   

    首先通常加速键是用来加速菜单项的,他经过TranslateAccelerator的处理,被翻译成WM_COMMAND或WM_SySCOMMAND然后直接发送给窗口处理函数,从而跳过TranslateMessage、DispatchMessage的处理,你的意思是,如果这时候按下的加速键是对应菜单项的,那么处理过程不变,按照正常的方式,但是,如果消息是发给Edit的Ctrl+Z,那么不按正常的加速键的处理方法,而是跳过ranslateAccelerator,把它当作普通的消息来TranslateMessage、DispatchMessage,那么我想接下来是不是应该在写一个处理WM_CHAR的函数,在这个函数里完成Edit的Ctrl+Z的处理.
    不知道理解得对不对.
      

  4.   

    还有如果是一个多文档应用程序,而且我打开了2个不同类型的文档,他们的菜单不同.第一个文档我要用Ctrl+Z,来加速菜单项"aaa";第二个文档我要用Ctrl+Z,来加速菜单项"bbb";那行不行,这下好像不是用你上面的方法把.是不是直接创建加速键就可以了.会不会乱掉啊
      

  5.   

    1.你前面贴出来的代码可以.那个消息最后被发到哪里去了??是不是被DispatchMessage到CEdit类去了.我原来以为是发到视图类去了.2."那就需要定义多套加速键".是不是在资源中创建2个加速键表.
      

  6.   

    是不是根据pMsg->hwnd来分发消息的
      

  7.   

    请问:
    WM_KEYDOWN('Z')应该不会再发给CEdit窗口了吧,发给他的是紧接下来的WM_CHAR('Z')吧,
      

  8.   

    WM_KEYDOWN('Z')怎么会发呢??BOOL CWinThread::PumpMessage()
    {
        _AFX_THREAD_STATE *pState = AfxGetThreadState();    ::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
     
        if (!AfxPreTranslateMessage(&(pState->m_msgCur)))
        {
            ::TranslateMessage(&(pState->m_msgCur));
            ::DispatchMessage(&(pState->m_msgCur));
        }
        return TRUE;
    }BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
    {
        ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
        ASSERT(pMsg != NULL);       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
    }
    从上面的代码可以看到只要返回TRUE,那么是不会调用 
    ::TranslateMessage(&(pState->m_msgCur));
    ::DispatchMessage(&(pState->m_msgCur));
    那么怎么发给他呢??
      

  9.   

    我说的是默认情况,如果自己在PreTranslateMessage中响应了该消息,消息就不会继续处理了。
      

  10.   

     if (pMsg->message == WM_KEYDOWN)
        {
            if (pMsg->hwnd == Edit句柄 && (GetAsyncKeyState(VK_CONTROL) & 0x8000) && pMsg->wParam == 'Z')
            {
                TranslateMessage(pMsg);  //产生WM_CHAR('Z'),即下一个GetMessage所获得的消息
                return TRUE;     //返回TRUE,所以本消息即WM_KEYDOWN("z")不会在继续处理.
            }
        }
        return 基类::PreTranslateMessage(pMsg);
    }
    这样理解应该没错把
      

  11.   

    那是不是可以证明,CEdit这个控件是在WM_ONCHAR('Z')这个消息里响应加速键Ctrl+Z(撤销)的
      

  12.   

    估计是这样,但不能肯定,你最好自己试一下,重载CEdit的OnChar函数,将Z屏蔽,看看还能不能撤消。
      

  13.   

    确实是在WM_ONCHAR('Z')这个地方处理的.但是有点奇怪按照上面的程序,我在PreTranslateMessage已经把WM_KEYDOWN("z")给屏蔽了,但是用SPY++跟踪CEdit窗口的消息时,还是可以看见WM_KEYDOWN("z")