如何在模态对话框中使用加速器表?

时间:2010-08-23 13:22:45

标签: winapi

我正在使用Win32 API进行编程,而不是MFC。

3 个答案:

答案 0 :(得分:1)

问题是DialogBox API没有要转换的加速器,必须在分派消息之前在消息循环上完成。

这个问题可以通过以下方式解决:

  • 使用SetWindowsHookEx API安装WH_GETMESSAGE类型的线程挂钩 - 这使您可以在消息返回DialogBox的消息循环之前查看消息
  • 关于钩子程序,过滤掉感兴趣的消息(PM_REMOVE,然后WM_KEYFIRST .. WM_LAST消息,然后窗口也是你感兴趣的)
  • 将邮件路由到TranslateAccelerator,如果成功,则通过MSG.mesasge更新WM_NULL以使其从API消息循环中“删除”来使其失效

2014年5月24日更新

用户Mick P.添加了一个遵循上述说明的代码段(出于某种原因,此处被同行评审拒绝了,但值得发布)并且他们的工作效果很好。这是代码(有些事情是有问题的,但对于需要快速启动的人来说,它总比没有好):

static HWND g_hDialog = NULL;
static HHOOK g_hHook = NULL;

static LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    LRESULT nResult = 1;
    if(nCode == HC_ACTION && wParam == PM_REMOVE)
    {
        MSG *p = (MSG*) lParam;
        if(p->message >= WM_KEYFIRST && p->message <= WM_KEYLAST)     
            if(g_hDialog == GetForegroundWindow())
            {
                HWND gf = GetFocus(); // ignore if edit-able control
                if(DLGC_HASSETSEL & ~SendMessage(gf, WM_GETDLGCODE, 0, 0)
                  || ES_READONLY & GetWindowLong(gf, GWL_STYLE)) 
                {
                    static HACCEL ha = // leaky
                        LoadAccelerators(..., MAKEINTRESOURCEW(IDR_MYACCEL));
                    if(TranslateAcceleratorW(g_hDialog, ha, p))
                    {
                        p->message = WM_NULL;
                        nResult = 0; 
                    }
                }
            }
    }
    if(nCode < 0 || nResult)
        return CallNextHookEx(g_hHook,nCode,wParam,lParam);
    return nResult;
}

static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Msg, 
  WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_INITDIALOG:
        g_hHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, ...,  GetCurrentThreadId());
        g_hDialog = hWnd;
        return 1;
    case WM_NCDESTROY:
        UnhookWindowsHookEx(g_hHook);
        break;
    }                                                                      
    return 0;
}

答案 1 :(得分:0)

确保您的消息泵中具有TranslateMessage(...)功能。如果是这样,加速键应该工作。实现模态对话框冻结应用程序中的所有其他窗口,直到它被解除。

BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{ 
    if( bRet == -1 )
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); //<< make sure this is present
        DispatchMessage(&msg); 
    }
}

确保在控制标题前放置一个&符号以“激活”加速度。示例:&amp;确定或&amp;取消。现在应该在第一个字母下面显示一个小的下划线,表明它有效。那封信成了加速键。它不一定是第一个字母。 E&放大器; XIT。线显示在“x”下,即加速键。

答案 2 :(得分:0)

请看这个例子http://msdn.microsoft.com/en-us/library/ms646337.aspx#editable_acc。可能你正在寻找什么。