[英]Embedding modeless dialogs as child window with Windows API
I know, there must be a way to embed an (modeless) dialog as child of a window created with CreateWindow
. 我知道,必须有一种方法可以将(无模式)对话框作为使用CreateWindow
创建的窗口的子级嵌入。 In my case I want to embed them into an scroll-able container window, whereby this container windows it self is a child of the main window (see picture). 就我而言,我想将它们嵌入可滚动显示的容器窗口中,由此,该容器窗口本身就是主窗口的子级(参见图片)。
The first problem that I encounter is, that I still want be able to use TAB keys and other dialog specific navigation. 我遇到的第一个问题是,我仍然希望能够使用TAB键和其他对话框特定的导航。 But how? 但是如何?
My message loop: 我的消息循环:
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsDialogMessage(msg.hwnd, &msg)) continue;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Edit: For testing purpose I modified the loop: 编辑:出于测试目的,我修改了循环:
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);
}
}
More information how to make it the right way can be found here: Using the TAB key to navigate in non-dialogs, redux 在此处可以找到如何正确设置的更多信息: 使用TAB键在非对话中导航,redux
With this message loop, nothing happens if I want to enter some dialog texts as if the message is not handled. 在此消息循环中,如果我想输入一些对话框文本,就像未处理消息一样,则什么也不会发生。 If IsDialogMessage
is removed, I can enter some text into an edit control in one of the embedded dialogs, however dialog navigation doesn't work as intended. 如果删除了IsDialogMessage
则可以在其中一个嵌入式对话框中的编辑控件中输入一些文本,但是对话框导航无法正常工作。 Of course, WS_TABSTOP
style is set for dialog child controls. 当然,为对话框子控件设置了WS_TABSTOP
样式。
The scroll-able container is created with CreateWindowEx
with styles WS_CHILD, WS_VISIBLE, WS_VSCROLL, WS_TABSTOP, WS_EX_CONTROLPARENT
and dialogs are created as children of this container. 使用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);
}
My GroupBarPanelInternalAddLast
modify modeless dialog styles by removing caption and borders, and ensures that WS_CHILD
, WS_VISIBLE
and WS_TABSTOP
is set ( SetWindowLong(hWndDlg, GWL_STYLE, ...)
). 我的GroupBarPanelInternalAddLast
通过删除标题和边框GroupBarPanelInternalAddLast
修改无模式对话框样式,并确保设置了WS_CHILD
, WS_VISIBLE
和WS_TABSTOP
( SetWindowLong(hWndDlg, GWL_STYLE, ...)
)。 (Also tested WS_EX_CONTROLPARENT
style) With SetParent(hWndDlg, hWndContainer)
modeless dialogs parent is changed. (还测试了WS_EX_CONTROLPARENT
样式)使用SetParent(hWndDlg, hWndContainer)
无模式对话框更改了父级对话框。
So what am I missing here? 那我在这里想念什么? As I found out, neither the container window procedure nor the embedded (for testing purpose subclassed) dialog procedure almost never gets WM_SETFOCUS
or WM_KILLFOCUS
messages for example, but why that? 正如我发现的那样,例如容器窗口过程和嵌入式(用于测试目的的子类化)对话框过程都几乎从不获取WM_SETFOCUS
或WM_KILLFOCUS
消息,但是为什么呢?
Solution: Calling IsDialogMessage for the top level window. 解决方案:在顶层窗口中调用IsDialogMessage。
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
if (IsDialogMessage(hWndTopLevel, &msg)) {
continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
You are not using IsDialogMessage()
correctly, and you said you learned from some bad tutorials. 您没有正确使用IsDialogMessage()
,并说您从一些错误的教程中学到了东西。 I don't know which tutorials you saw, so I can't tell you what they got wrong; 我不知道您看到了哪些教程,所以无法告诉您他们错了什么。 all I can do is say how to use it correctly. 我所能做的就是说如何正确使用它。
IsDialogMessage()
takes two parameters: the message itself, and the window handle of the toplevel window . IsDialogMessage()
具有两个参数:消息本身和顶级window的窗口句柄。 This bit in bold is the important part: the IsDialogMessage()
function needs to know which dialog to work with in the event of tab navigation or Enter/Esc handling. 粗体字的这一部分是重要的组成部分:在选项卡导航或Enter / Esc处理的情况下, IsDialogMessage()
函数需要知道要使用哪个对话框。
You don't want to pass msg.hwnd
; 你不想通过msg.hwnd
; that's the control itself. 那就是控件本身。
And in the case of nested child dialogs like you have here, you don't want to pass in the child dialog's handle; 对于像您在此处这样的嵌套子对话框,您也不想传递子对话框的句柄。 that would confine IsDialogMessage()
to that dialog. 将IsDialogMessage()
限制在该对话框中。
So in your screenshot, you want to pass in the handle of the main window, that is, the window called Win32ApiDemo1
. 因此,在屏幕截图中,您希望传递主窗口的句柄,即名为Win32ApiDemo1
的窗口。
Also make sure all the child dialogs and your custom expander control have WS_EX_CONTROLPARENT
so tab navigation can recurse. 还要确保所有子对话框和您的自定义扩展器控件都具有WS_EX_CONTROLPARENT
以便可以递归选项卡导航。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.