2016-06-29 13 views
1

Я знаю, что должен быть способ встроить диалоговое окно (немодальное) в качестве дочернего элемента окна, созданного с помощью CreateWindow. В моем случае я хочу встроить их в окно контейнера с возможностью прокрутки, в котором окна этого контейнера сами являются дочерними элементами главного окна (см. Рисунок).Внедрение немодальных диалогов в виде дочернего окна с Windows API

Embedded Dialogs

Первая проблема, с которой я сталкиваюсь в том, что я все еще хочу быть в состоянии использовать клавиши TAB и другие диалоговую конкретную навигацию. Но как?

Мой цикл сообщений:

while (GetMessage(&msg, NULL, 0, 0)) { 
    if (IsDialogMessage(msg.hwnd, &msg)) continue; 
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

Edit: Для целей тестирования я модифицировал цикл:

while (GetMessage(&msg, NULL, 0, 0)) { 
    if (IsEmbeddedDialogWindow(msg.hwnd)) { 
     if (IsDialogMessage(msg.hwnd, &msg)) continue; 
    } 
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

while (GetMessage(&msg, NULL, 0, 0)) { 
    if (IsScrollableContainerWindow(msg.hwnd)) { 
     if (IsDialogMessage(msg.hwnd, &msg)) continue; 
    } 
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

Более подробная информация, как сделать это правильно, можно найти здесь: Using the TAB key to navigate in non-dialogs, redux

С помощью этого цикла сообщений ничего не происходит, если я хочу ввести некоторые диалоговые тексты, как если бы сообщение не обрабатывалось. Если удаляется IsDialogMessage, я могу ввести какой-либо текст в элемент управления редактирования в одном из встроенных диалогов, однако диалог не работает так, как предполагалось. Конечно, для элементов управления диалогового окна установлен стиль WS_TABSTOP.

Прокручиваемый контейнер создается с помощью CreateWindowEx со стилями WS_CHILD, WS_VISIBLE, WS_VSCROLL, WS_TABSTOP, WS_EX_CONTROLPARENT и диалоги создаются как дети этого контейнера.

HWND hWndContainer = GroupBarPanelCreate(WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, WS_EX_CONTROLPARENT, hWndMain, 0, 0, 400, 400); 
    GROUPBAR_PANEL* GroupBarPanel = (GROUPBAR_PANEL*) GetWindowLongPtr(hWndContainer, 0); 
    // Test embedding dialogs 
    for (unsigned int i = 0; i < 10; i++) { 
     HWND hWndDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWndContainer, About, 0); 
     GroupBarPanelInternalAddLast(GroupBarPanel, hWndChild, hWndDlg, nullptr); 
    } 

Мои GroupBarPanelInternalAddLast изменить безрежимные диалоговые стили путем удаления заголовка и границ, а также гарантирует, что WS_CHILD, WS_VISIBLE и WS_TABSTOP устанавливается (SetWindowLong(hWndDlg, GWL_STYLE, ...)). (Также проверено WS_EX_CONTROLPARENT стиль) С SetParent(hWndDlg, hWndContainer) изменен родительский диалог.

Working Demo

Так что я здесь отсутствует? Как я выяснил, ни процедура окна контейнера, ни встроенная (для проверки цели подкласса) процедура диалога почти никогда не получает WM_SETFOCUS или WM_KILLFOCUS сообщений, но почему это?

Вызов IsDialogMessage для окна верхнего уровня.

while (GetMessage(&msg, NULL, 0, 0)) { 
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 
     if (IsDialogMessage(hWndTopLevel, &msg)) { 
      continue; 
     } 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 
+1

'IsDialogMessage' необходимо передать« HWND »диалогового окна кандидата, а не окно, на которое нацелено сообщение. –

+0

Ну, ему должно быть предоставлено 'HWND' окна, которое имеет стиль' WS_EX_CONTROLPARENT' и является родителем других диалогов. –

+2

При создании вам необходимо вручную установить фокус ввода, иначе клавиатурная навигация не будет работать. Я не совсем уверен, что это можно сделать для надежной работы. Почему вы не создаете обычные окна? – IInspectable

ответ

2

Вы не используете IsDialogMessage() правильно, и вы сказали, что вы узнали от некоторых плохих учебников. Я не знаю, какие учебники вы видели, поэтому я не могу сказать вам, что они ошибались; все, что я могу сделать, это сказать, как правильно использовать его.

IsDialogMessage() принимает два параметра: само сообщение и дескриптор окна окна верхнего уровня . Этот бит выделен жирным шрифтом - важная часть: функция IsDialogMessage() должна знать, с каким диалогом работать в случае навигации по вкладке или вводом/выводом.

Вы не хотите передавать msg.hwnd; это сам контроль.

И в случае вложенных дочерних диалоговых окон, подобных вам, вы не хотите проходить в дескрипторе дочернего диалога; который ограничил бы IsDialogMessage() в этом диалоговом окне.

Так что на скриншоте вы хотите передать в ручку главного окна, то есть окно под названием Win32ApiDemo1.

Также убедитесь, что все дочерние диалоги и ваш пользовательский элемент управления расширителем имеют WS_EX_CONTROLPARENT, поэтому можно переходить к навигации по вкладкам.