2016-06-29 4 views
1

Je sais, il doit y avoir un moyen d'intégrer un (modales) dialogue comme enfant d'une fenêtre créée avec CreateWindow. Dans mon cas, je veux les incorporer dans une fenêtre de conteneur défilante, dans laquelle ce conteneur est lui-même un enfant de la fenêtre principale (voir image).Enrobage boîtes de dialogue modales comme fenêtre enfant avec Windows API

Embedded Dialogs

Le premier problème que je rencontre est que je veux toujours être en mesure d'utiliser les touches TAB et autres navigation spécifiques de dialogue. Mais comment?

Ma boucle de message:

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

Edit: Pour des fins d'essai I modifié la boucle:

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); 
    } 
} 

Plus d'informations comment faire de la bonne façon se trouve ici: Using the TAB key to navigate in non-dialogs, redux

Avec cette boucle de message, rien ne se passe si je veux saisir des textes de dialogue comme si le message n'est pas manipulé. Si IsDialogMessage est supprimé, je peux entrer du texte dans un contrôle d'édition dans l'une des boîtes de dialogue intégrées, mais la navigation dans les boîtes de dialogue ne fonctionne pas comme prévu. Bien sûr, le style WS_TABSTOP est défini pour les contrôles enfants de boîte de dialogue.

Le récipient de mesure de défilement est créé avec CreateWindowEx avec des styles WS_CHILD, WS_VISIBLE, WS_VSCROLL, WS_TABSTOP, WS_EX_CONTROLPARENT et les dialogues sont créés comme des enfants de ce conteneur.

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); 
    } 

Ma GroupBarPanelInternalAddLast modifier les styles de dialogue non modale en enlevant la légende et des frontières, et veille à ce que WS_CHILD, WS_VISIBLE et WS_TABSTOP est réglé (SetWindowLong(hWndDlg, GWL_STYLE, ...)). (Également testé style WS_EX_CONTROLPARENT) Avec SetParent(hWndDlg, hWndContainer) boîtes de dialogue non modales parent est changé.

Working Demo

Alors qu'est-ce que je manque ici? Comme je l'ai découvert, ni la procédure de fenêtre de contenant ni incorporé (à des fins de test sous-classé) procédure de dialogue presque jamais obtient WM_SETFOCUS ou WM_KILLFOCUS messages par exemple, mais pourquoi cela?

Solution: Appel de IsDialogMessage pour la fenêtre de niveau supérieur.

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

'IsDialogMessage' doit être passé à' HWND' de la boîte de dialogue candidate, et non à la fenêtre ciblée. –

+0

Eh bien, il devrait être donné le 'HWND' de la fenêtre qui a le style' WS_EX_CONTROLPARENT', et qui est le parent des autres boîtes de dialogue. –

+2

Lors de la création, vous devez définir manuellement le focus d'entrée, sinon la navigation au clavier ne fonctionnera pas. Je ne suis pas entièrement convaincu que cela puisse fonctionner de manière fiable. Pourquoi ne créez-vous pas des fenêtres régulières à la place? – IInspectable

Répondre

2

Vous n'utilisez pas correctement IsDialogMessage(), et vous avez dit que vous avez appris de quelques mauvais tutoriels. Je ne sais pas quels tutoriels vous avez vu, donc je ne peux pas vous dire ce qu'ils ont eu de mal; Tout ce que je peux faire, c'est dire comment l'utiliser correctement.

IsDialogMessage() prend deux paramètres: le message lui-même et le handle de fenêtre de la fenêtre de niveau . Ce bit en gras est la partie importante: la fonction IsDialogMessage() doit savoir quelle boîte de dialogue utiliser en cas de navigation par onglets ou de gestion Entrée/Echap.

Vous ne voulez pas passer msg.hwnd; c'est le contrôle lui-même.

Et dans le cas de boîtes de dialogue enfant imbriquées comme vous avez ici, vous ne voulez pas passer dans le handle de la boîte de dialogue enfant; cela limiterait IsDialogMessage() à cette boîte de dialogue.

Donc, dans votre capture d'écran, vous voulez passer dans la poignée de la fenêtre principale, c'est-à-dire la fenêtre appelée Win32ApiDemo1.

Assurez-vous également que toutes les boîtes de dialogue enfant et votre contrôle expander personnalisé ont WS_EX_CONTROLPARENT afin que la navigation par onglets puisse être recurrée.