剧情简介
当在下面的行中调用
AppendMenu
时,使用 CreateWindowW
实例化的 GUI 菜单栏会消失。
CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 200, 152, 100, 50, hWnd, NULL, NULL, NULL);
对
CreateWindowW
的调用会创建一个文本输入框。
以下两张图显示了 GUI 窗口,其中 (1) 和 (2) 没有注释掉上述代码行。
代码
#include <Windows.h>
#include <sal.h>
constexpr auto FILE_DROPDOWN_ID = 1;
constexpr auto HELP_POPUP_ID = 2;
constexpr auto LOAD_DROPDOWN_ID = 3;
constexpr auto LOAD_TSD_NO_OFFSET = 4;
constexpr auto FILE_MENU_EXIT = 5;
constexpr auto CHANGE_TITLE = 6;
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
void AddMenusAndControls(HWND);
HMENU hMenu;
//int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow) {
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
//MessageBox(NULL, L"Upconverter Start up", L"Please load your file", MB_OK);
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // Define window background
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInstance;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc)) // Pass as reference because arg is type pointer
return -1;
CreateWindowW(L"myWindowClass", L"My Window Name", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 200, 500, 500,
NULL, NULL, NULL, NULL);
// Event driven loop
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
switch (msg)
{
case WM_COMMAND: // Triggered for every button or menu item. Tells us that something has been clicked.
switch (wp) // This switch statement governs the resultant behavior of a button press on the main window.
{
//case FILE_DROPDOWN_ID:
//MessageBeep(MB_DEFBUTTON1);
case HELP_POPUP_ID:
MessageBeep(MB_DEFBUTTON2);
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
case LOAD_DROPDOWN_ID:
MessageBeep(MB_ICONINFORMATION);
break;
case CHANGE_TITLE:
break;
}
case WM_CREATE:
//AddControls(hWnd);
//AddMenus(hWnd);
AddMenusAndControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefMDIChildProcW(hWnd, msg, wp, lp);
}
}
void AddMenusAndControls(HWND hWnd) {
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"File");
AppendMenu(hFileMenu, MF_STRING, LOAD_DROPDOWN_ID, L"New");
AppendMenu(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"Open Submenu");
AppendMenu(hSubMenu, MF_STRING, CHANGE_TITLE, L"Change Title");
AppendMenu(hFileMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_EXIT, L"Exit");
AppendMenu(hMenu, MF_STRING, HELP_POPUP_ID, L"Help");
CreateWindowW(L"static", L"Enter text here: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 50, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 200, 152, 100, 50, hWnd, NULL, NULL, NULL); // WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL
SetMenu(hWnd, hMenu);
}
void AddMenus(HWND hWnd) {
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hSubMenu, MF_STRING, CHANGE_TITLE, L"Change Title");
AppendMenu(hFileMenu, MF_STRING, LOAD_DROPDOWN_ID, L"New");
AppendMenu(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"Open Submenu");
AppendMenu(hFileMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_EXIT, L"Exit");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"File");
AppendMenu(hMenu, MF_STRING, HELP_POPUP_ID, L"Help");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd) {
CreateWindowW(L"static", L"Enter text here: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 50, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 200, 152, 100, 50, hWnd,
NULL, NULL, NULL); // WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL
}
讨论
我怀疑这与窗口句柄
hWnd
有关,允许覆盖窗口内容。所以我改变了之前的两遍hWnd
case WM_CREATE:
AddControls(hWnd);
AddMenus(hWnd);
单个函数调用。
case WM_CREATE:
AddMenusAndControls(hWnd);
但这没有效果。它也可能与
SetMenu
有关,但我不确定以什么方式。我尝试将 SetMenu
调用移至 AddMenusAndControls
中的不同行,但这也没有效果。
这是怎么回事?
感谢您的帮助。
你的窗口程序被严重破坏了。它具有非 void 返回类型,但到达末尾时不会沿除
default:
之外的所有路径返回任何内容。
窗口过程的正确结构是在函数末尾无条件地调用默认窗口过程。任何不应传递给默认窗口过程的消息都需要通过
case
(并指定返回值)而不是 return
退出其 break
。
改变
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefMDIChildProcW(hWnd, msg, wp, lp);
}
到
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hWnd, msg, wp, lp);
我还修复了您对要调用的默认窗口过程的选择,因为您的 WinMain 似乎将此窗口用作顶级框架,而不是 MDI 子窗口。 因为当焦点更改时,MDI 子控件会自动将其菜单迁移到 MDI 父控件,并且因为您要添加一个能够接收焦点的新子控件(在框架获得焦点之前),所以很可能发送与焦点相关的消息到你的窗口更改,并且由于你尽职尽责地转发了它们,你得到了你所要求的 MDI 菜单行为(即使你不想要它)。如果您没有 MDI,请勿使用
DefMDIChildProcW
!
switch (wp) // This switch statement governs the resultant behavior of a button press on the main window.
{
//case FILE_DROPDOWN_ID:
//MessageBeep(MB_DEFBUTTON1);
case HELP_POPUP_ID:
MessageBeep(MB_DEFBUTTON2);
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
case LOAD_DROPDOWN_ID:
MessageBeep(MB_ICONINFORMATION);
break;
case CHANGE_TITLE:
break;
}
break; ///THIS WAS CAUSING ERROR ADD THIS BREAK;
case WM_CREATE:
//AddControls(hWnd);
//AddMenus(hWnd);
AddMenusAndControls(hWnd);
break;