我想在单击将成为主窗口子窗口的菜单项时使用CreateWindow()创建一个窗口。我知道我可以使用DialogBox()或CreateDialog(),但我想使用CreateWindow()。我在用这个密码
资源.rc文件
#include "resource.h"
IDM_MENU MENU
{
POPUP "&Help"
{
MENUITEM "&About", IDM_HELP
}
}
关于窗口过程
LRESULT CALLBACK AboutProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
主窗口过程
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_HELP:
{
WNDCLASSEX wc;
HWND hDlg;
MSG msg;
SecureZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = (HICON)GetClassLong(hwnd, GCL_HICON);
wc.hIconSm = (HICON)GetClassLong(hwnd, GCL_HICONSM);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = AboutProc;
wc.lpszClassName = TEXT("AboutClass");
if(!RegisterClassEx(&wc))
break;
hDlg = CreateWindowEx(0, wc.lpszClassName, TEXT("About"), WS_OVERLAPPEDWINDOW, 0, 0, 300, 200, hwnd, 0, wc.hInstance, 0);
ShowWindow(hDlg, SW_SHOWNORMAL);
while(GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnregisterClass(wc.lpszClassName, wc.hInstance);
}
break;
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
这是个好主意吗?您可以在同一个示例中注册多个类吗?另外,将主窗口图标分配给这个子窗口是一个好主意,还是每次都加载它们?当我在IDM_HELP中调用UnregisterClass()时,这些图标会被删除吗?我试过这个程序,一切正常,图标仍然显示在主窗口后,我关闭这个子窗口。但是我仍然怀疑是否可以将主窗口图标分配给这个窗口,因为我在子窗口关闭后调用了UnregisterClass()
2条答案
按热度按时间dbf7pr2w1#
使用
CreateWindow/Ex()
而不是CreateDialog()
/DialogBox()
没有任何问题。运行你自己的模态消息循环没有什么错,只要你正确地实现它。例如,请注意以下警告:Modality, part 3: The WM_QUIT message
关于模态的另一个重要的事情是WM_QUIT消息总是打破模态循环。在你自己的模态循环中记住这一点!如果调用PeekMessage函数或GetMessage函数并获得WM_QUIT消息,则不仅必须退出模态循环,而且还必须重新生成WM_QUIT消息(通过PostQuitMessage消息),以便下一个外层将看到WM_QUIT消息并进行清理。如果您未能传播消息,下一个外层将不知道它需要退出,并且程序将似乎“卡在”其关闭代码中,迫使用户以艰难的方式终止进程。
你展示的例子没有做到这一点,所以你需要添加它:
然而,你的模态窗口不应该仅仅为了打破它的模态循环而使用
WM_QUIT
,因为这样做会退出你的整个应用程序!当窗口关闭时,使用不同的信号使模态循环中断。例如:此外,模态窗口应该禁用其所有者窗口,然后在关闭时重新启用它。你的例子也没有做到这一点,所以也需要添加:
Old New Thing博客有一系列关于如何使用模态窗口的文章。
Modality, part 1: UI-modality vs code-modality
Modality, part 2: Code-modality vs UI-modality
Modality, part 3: The WM_QUIT message
Modality, part 4: The importance of setting the correct owner for modal UI
Modality, part 5: Setting the correct owner for modal UI
Modality, part 6: Interacting with a program that has gone modal
Modality, part 7: A timed MessageBox, the cheap version
Modality, part 8: A timed MessageBox, the better version
Modality, part 9: Setting the correct owner for modal UI, practical exam
The correct order for disabling and enabling windows
Make sure you disable the correct window for modal UI
更新:根据您的评论“不,我不想要模态窗口”,您可以忽略上面的所有内容。所有这些都只适用于模式窗口。既然您不想要模态窗口,那么只需完全删除辅助循环,让主消息循环处理所有事情。另外,您不需要调用
UnregisterClass()
。它将在进程结束时自动注销。调用RegisterClass()
一次,可以在程序启动时,或者至少在第一次显示“About”窗口时。您可以使用GetClassInfo/Ex()
来了解类是否已经注册,或者自己跟踪它。试想一下,如果用户希望在进程的生存期内多次显示“关于”窗口,会发生什么情况。因此,让它每次都重用现有的类注册。试试这个:
byqmnocz2#
可以使用
CreateWindow()
。你可以在你的事件处理器中做任何事情。使用DialogBox()
只是免费提供了一个模态循环(因此在对话框关闭之前,无法与主窗口交互)。是的,您可以注册多个窗口类。你可以自由地提前注册你所有的窗口课程;你不需要每次有人点击你的菜单项时调用
RegisterClass()
和UnregisterClass()
。我不确定
UnregisterClass()
是否释放了分配给窗口类的各种GDI资源;任何知道答案的人都可以自由发表评论。