gpt4 book ai didi

单击菜单命令时使用 createwindow() 创建窗口

转载 作者:太空宇宙 更新时间:2023-11-04 06:24:11 25 4
gpt4 key购买 nike

我想在单击将成为主窗口子项的菜单项时使用 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()

最佳答案

使用 CreateWindow/Ex() 而不是 CreateDialog()/DialogBox() 没有任何问题。运行您自己的模态消息循环没有任何问题,只要您正确地实现它。例如,请注意此警告:

Modality, part 3: The WM_QUIT message

The other important thing about modality is that a WM_QUIT message always breaks the modal loop. Remember this in your own modal loops! If ever you call the PeekMessage function or the GetMessage function and get a WM_QUIT message, you must not only exit your modal loop, but you must also re-generate the WM_QUIT message (via the PostQuitMessage message) so the next outer layer will see the WM_QUIT message and do its cleanup as well. If you fail to propagate the message, the next outer layer will not know that it needs to quit, and the program will seem to "get stuck" in its shutdown code, forcing the user to terminate the process the hard way.

您展示的示例没有这样做,因此您需要添加它:

ShowWindow(hDlg, SW_SHOWNORMAL);

do
{
BOOL bRet = GetMessage(&msg, 0, 0, 0);
if (bRet > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
if (bRet == 0)
PostQuitMessage(msg.wParam); // <-- add this!
break;
}
}
while (1);

UnregisterClass(wc.lpszClassName, wc.hInstance);

但是,您的模态窗口不应该使用 WM_QUIT 来打破它的模态循环,因为这样做会退出您的整个应用程序!使用不同的信号使您的模态循环在窗口关闭时中断。例如:

ShowWindow(hDlg, SW_SHOWNORMAL);

while (IsWindow(hDlg) && (GetMessage(&msg, 0, 0, 0) > 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

LRESULT CALLBACK AboutProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}

return 0;
}

此外,模态窗口应该禁用其所有者窗口,然后在关闭时重新启用它。您的示例也没有这样做,因此也需要添加:

ShowWindow(hDlg, SW_SHOWNORMAL);
EnableWindow(hwnd, FALSE); // <-- add this
...

LRESULT CALLBACK AboutProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
EnableWindow(GetWindow(hwnd, GW_OWNER), TRUE); // <-- add this
DestroyWindow(hwnd);
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}

return 0;
}

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() 一次,可以在程序启动时调用,或者至少在您第一次显示“关于”窗口时调用。您可以使用 GetClassInfo/Ex() 来了解该类是否已注册,或自行跟踪。想一想如果用户想要在进程的生命周期内多次显示“关于”窗口会发生什么。因此,让它每次都重新使用现有的类注册。

试试这个:

LRESULT CALLBACK AboutProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
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 = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.hInstance = GetModuleHandle(0);
wc.lpszClassName = TEXT("AboutClass");

if (!GetClassInfoEx(wc.hInstance, wc.lpszClassName, &wc))
{
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.lpfnWndProc = AboutProc;

if (!RegisterClassEx(&wc))
break;
}

HWND hDlg = CreateWindowEx(0, wc.lpszClassName, TEXT("About"), WS_OVERLAPPEDWINDOW, 0, 0, 300, 200, hwnd, 0, wc.hInstance, 0);

if (hDlg)
ShowWindow(hDlg, SW_SHOWNORMAL);
}
break;
}
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

关于单击菜单命令时使用 createwindow() 创建窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29359160/

25 4 0