使用Windows API将无模式对话框嵌入为子窗口

时间:2016-06-29 06:41:58

标签: c winapi dialog childwindow createwindow

我知道,必须有一种方法可以将(无模式)对话框嵌入到使用CreateWindow创建的窗口的子窗口中。在我的情况下,我想将它们嵌入到一个可滚动的容器窗口中,这个容器窗口自己就是主窗口的子窗口(见图)。

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

编辑:出于测试目的,我修改了循环:

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_CHILDWS_VISIBLEWS_TABSTOPSetWindowLong(hWndDlg, GWL_STYLE, ...))。 (还测试了WS_EX_CONTROLPARENT样式)使用SetParent(hWndDlg, hWndContainer)无模式对话框,父级已更改。

Working Demo

那我在这里错过了什么?正如我所发现的那样,容器窗口过程和嵌入式(用于测试目的子类)对话程序几乎都不会得到WM_SETFOCUSWM_KILLFOCUS消息,例如,为什么呢?

解决方案:为顶级窗口调用IsDialogMessage。

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

1 个答案:

答案 0 :(得分:2)

你没有正确使用IsDialogMessage(),而且你说你从一些不好的教程中学到了什么。我不知道你看过哪些教程,所以我不能告诉你他们错了什么;我所能做的只是说明如何正确使用它。

IsDialogMessage()有两个参数:消息本身和顶层窗口的窗口句柄。这个粗体位是重要部分:IsDialogMessage()函数需要知道在选项卡导航或Enter / Esc处理时使用哪个对话框。

您不想传递msg.hwnd;这就是控制本身。

对于像这里一样的嵌套子对话框,你不想传入子对话框的句柄;这会将IsDialogMessage()限制在该对话框中。

因此,在屏幕截图中,您希望传递主窗口的句柄,即名为Win32ApiDemo1的窗口。

还要确保所有子对话框和自定义扩展程序控件都有WS_EX_CONTROLPARENT,以便标签导航可以递归。