Как использовать таблицу акселераторов в модальном диалоговом окне? - PullRequest
1 голос
/ 23 августа 2010

Я программирую с Win32 API, а не с MFC.

Ответы [ 3 ]

1 голос
/ 11 января 2014

Проблема в том, что DialogBox API не имеет ускорителей для перевода, и это должно быть сделано в цикле сообщений перед отправкой сообщений.

Эту проблему можно решить следующим образом:

  • используйте SetWindowsHookEx API для установки ловушки потока типа WH_GETMESSAGE - это позволяет вам видеть сообщения до того, как они будут возвращены в цикл сообщений DialogBox
  • на подключаемой процедуре, отфильтруйте интересующие сообщения (PM_REMOVE, затем сообщение WM_KEYFIRST .. WM_LAST, затем окно также представляет интерес)
  • перенаправить сообщение на TranslateAccelerator и в случае успеха аннулировать его, обновив MSG.mesasge с помощью WM_NULL, чтобы «удалить» его из цикла сообщений API

24 мая 2014 г. Обновление

Пользователь Мик П. добавил фрагмент кода, который следует инструкциям выше (по какой-то причине это было отклонено при рецензировании здесь, но это стоит опубликовать), и они хорошо сработали для него. Вот код (некоторые вещи сомнительны, но это лучше, чем ничего для тех, кому требуется быстрый старт):

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;
}
0 голосов
/ 24 августа 2010

Посмотрите на этот пример http://msdn.microsoft.com/en-us/library/ms646337.aspx#editable_acc. Возможно, это то, что вы ищете.

0 голосов
/ 23 августа 2010

Убедитесь, что в насосе сообщений есть функция 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); 
    }
}

Убедитесь, что поставили амперсанд перед надписью, чтобы «активировать» ускорение. Пример: & OK или & Cancel. Небольшое подчеркивание теперь должно отображаться под первой буквой, указывающей, что это работает И это письмо становится ключом ускорения. Это не должно быть первая буква. Выход. Линия отображается под «х», и это клавиша ускорения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...