菜单按钮触发另一个 window
Menu button triggering another window
我是 c++ 的新手,已经开始了解 Win32 GUI。我试图让一个子菜单按钮打开一个 window,它将显示一个计算器 window,但是我似乎无法通过做合乎逻辑的事情来弄清楚它,我找不到任何有用的东西在线的。请帮忙! P.S 它要我写更多的细节,所以...我尝试在 WM_COMMAND windows 过程中使用 CreateWindowW() 函数,但命令与按钮的 ID。然而,虽然它仍然 运行,但它实际上没有做任何事情。
#include <windows.h>
#include <iostream>
#include <fstream>
#define FILE_MENU_NEW 1
#define FILE_MENU_OPEN 2
#define FILE_MENU_EXIT 3
#define ID_GO 4
#define BUTTON_CALCULATOR 5
LRESULT CALLBACK WindowProcedure(HWND,UINT,WPARAM,LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
HMENU hMenu;
HWND login;
HWND button;
HWND usernameText;
HWND passwordText;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args,int ncmdshow)
{
WNDCLASSW wc = {0};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProcedure;
if(!RegisterClassW(&wc))
return -1;
CreateWindowW(L"myWindowClass",L"My Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,1000,800,NULL,NULL,NULL,NULL);
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:
switch(wp)
{
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
MessageBeep(MB_OK);
break;
case FILE_MENU_NEW:
break;
case ID_GO:
//Work in progress
wchar_t usernameInput[100];
wchar_t passwordInput[100];
GetWindowTextW(usernameText,usernameInput,100);
GetWindowTextW(passwordText,passwordInput,100);
break;
case BUTTON_CALCULATOR:
MessageBeep(MB_OK);
CreateWindowW(L"calculatorClass",L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,NULL,NULL,NULL,NULL);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
void AddMenus(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hToolMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hSubMenu,MF_STRING,NULL,"Note");
AppendMenu(hFileMenu,MF_POPUP,(UINT_PTR)hSubMenu,"New");
AppendMenu(hFileMenu,MF_STRING,FILE_MENU_OPEN,"Open");
AppendMenu(hFileMenu,MF_SEPARATOR,NULL,NULL);
AppendMenu(hFileMenu,MF_STRING,FILE_MENU_EXIT,"Exit");
AppendMenu(hToolMenu,MF_STRING,BUTTON_CALCULATOR,"Calculator");
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hFileMenu,"File");
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hToolMenu,"Tools");
SetMenu(hWnd,hMenu);
}
void AddControls(HWND hWnd)
{
CreateWindowW(L"static",L"Login:",WS_VISIBLE | WS_CHILD| SS_RIGHT, 50,50,80,20,hWnd,NULL,NULL,NULL);
usernameText = CreateWindowW(L"edit",L"", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 140,50,80,20,hWnd,NULL,NULL,NULL);
CreateWindowW(L"static",L"Password:",WS_VISIBLE | WS_CHILD| SS_RIGHT, 50,90,80,20,hWnd,NULL,NULL,NULL);
passwordText = CreateWindowW(L"edit",L"", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 140,90,80,20,hWnd,NULL,NULL,NULL);
button = CreateWindowW(L"button", L"GO", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,250,65,50,30,hWnd,(HMENU)ID_GO,NULL,NULL);
}
您的 WM_COMMAND
处理程序检查 WPARAM
值不正确。
WPARAM
值的 LOWORD 包含发送 WM_COMMAND
消息的项目的 ID,HIWORD
包含通知代码,例如 BN_CLICKED
,等等。您完全忽略了 HIWORD
。您的 switch(wp)
语句仅适用于 HIWORD
为 0 的菜单项,但不适用于 HIWORD 不为 0 的按钮点击等操作。您的 ID_GO
控件是一个按钮,而不是一个菜单项,所以 wp
参数永远不会完全是 ID_GO
你的 switch(wp)
语句找到 case
for.
至少,您需要将 switch(wp)
改为 switch(LOWORD(wp))
:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
switch (LOWORD(wp))
{
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
MessageBeep(MB_OK);
break;
case FILE_MENU_NEW:
break;
case ID_GO:
{
//Work in progress
wchar_t usernameInput[100];
wchar_t passwordInput[100];
GetWindowTextW(usernameText,usernameInput,100);
GetWindowTextW(passwordText,passwordInput,100);
}
break;
}
case BUTTON_CALCULATOR:
MessageBeep(MB_OK);
CreateWindowW(L"calculatorClass",L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,NULL,NULL,NULL,NULL);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}
但是,更重要的是,"calculatorClass"
window class 没有调用 RegisterClassW()
,例如:
WNDCLASSW wc = {0};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"calculatorClass";
wc.lpfnWndProc = CalculatorWindowProcedure;
RegisterClassW(&wc)
您如何期望 CreateWindowW()
为它不知道的 class 创建一个 window?您的代码也没有检查 CreateWindowW()
调用是否失败,例如:
hCalcWnd = CreateWindowW(L"calculatorClass",L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,NULL,NULL,NULL,NULL);
if (!hCalcWnd)
{
DWORD err = GetLastError(); // ERROR_CLASS_DOES_NOT_EXIST, etc...
...
}
附带说明一下,您没有为 File|New
子菜单上的 "Note"
项目分配 ID。为了与 File
菜单项保持一致,您应该考虑将 BUTTON_CALCULATOR
重命名为 TOOL_MENU_CALCULATOR
之类的名称。也许将 ID_GO
重命名为 BUTTON_GO
.
我是 c++ 的新手,已经开始了解 Win32 GUI。我试图让一个子菜单按钮打开一个 window,它将显示一个计算器 window,但是我似乎无法通过做合乎逻辑的事情来弄清楚它,我找不到任何有用的东西在线的。请帮忙! P.S 它要我写更多的细节,所以...我尝试在 WM_COMMAND windows 过程中使用 CreateWindowW() 函数,但命令与按钮的 ID。然而,虽然它仍然 运行,但它实际上没有做任何事情。
#include <windows.h>
#include <iostream>
#include <fstream>
#define FILE_MENU_NEW 1
#define FILE_MENU_OPEN 2
#define FILE_MENU_EXIT 3
#define ID_GO 4
#define BUTTON_CALCULATOR 5
LRESULT CALLBACK WindowProcedure(HWND,UINT,WPARAM,LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
HMENU hMenu;
HWND login;
HWND button;
HWND usernameText;
HWND passwordText;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args,int ncmdshow)
{
WNDCLASSW wc = {0};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProcedure;
if(!RegisterClassW(&wc))
return -1;
CreateWindowW(L"myWindowClass",L"My Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,1000,800,NULL,NULL,NULL,NULL);
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:
switch(wp)
{
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
MessageBeep(MB_OK);
break;
case FILE_MENU_NEW:
break;
case ID_GO:
//Work in progress
wchar_t usernameInput[100];
wchar_t passwordInput[100];
GetWindowTextW(usernameText,usernameInput,100);
GetWindowTextW(passwordText,passwordInput,100);
break;
case BUTTON_CALCULATOR:
MessageBeep(MB_OK);
CreateWindowW(L"calculatorClass",L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,NULL,NULL,NULL,NULL);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
void AddMenus(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hToolMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hSubMenu,MF_STRING,NULL,"Note");
AppendMenu(hFileMenu,MF_POPUP,(UINT_PTR)hSubMenu,"New");
AppendMenu(hFileMenu,MF_STRING,FILE_MENU_OPEN,"Open");
AppendMenu(hFileMenu,MF_SEPARATOR,NULL,NULL);
AppendMenu(hFileMenu,MF_STRING,FILE_MENU_EXIT,"Exit");
AppendMenu(hToolMenu,MF_STRING,BUTTON_CALCULATOR,"Calculator");
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hFileMenu,"File");
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hToolMenu,"Tools");
SetMenu(hWnd,hMenu);
}
void AddControls(HWND hWnd)
{
CreateWindowW(L"static",L"Login:",WS_VISIBLE | WS_CHILD| SS_RIGHT, 50,50,80,20,hWnd,NULL,NULL,NULL);
usernameText = CreateWindowW(L"edit",L"", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 140,50,80,20,hWnd,NULL,NULL,NULL);
CreateWindowW(L"static",L"Password:",WS_VISIBLE | WS_CHILD| SS_RIGHT, 50,90,80,20,hWnd,NULL,NULL,NULL);
passwordText = CreateWindowW(L"edit",L"", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 140,90,80,20,hWnd,NULL,NULL,NULL);
button = CreateWindowW(L"button", L"GO", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,250,65,50,30,hWnd,(HMENU)ID_GO,NULL,NULL);
}
您的 WM_COMMAND
处理程序检查 WPARAM
值不正确。
WPARAM
值的 LOWORD 包含发送 WM_COMMAND
消息的项目的 ID,HIWORD
包含通知代码,例如 BN_CLICKED
,等等。您完全忽略了 HIWORD
。您的 switch(wp)
语句仅适用于 HIWORD
为 0 的菜单项,但不适用于 HIWORD 不为 0 的按钮点击等操作。您的 ID_GO
控件是一个按钮,而不是一个菜单项,所以 wp
参数永远不会完全是 ID_GO
你的 switch(wp)
语句找到 case
for.
至少,您需要将 switch(wp)
改为 switch(LOWORD(wp))
:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
switch (LOWORD(wp))
{
case FILE_MENU_EXIT:
DestroyWindow(hWnd);
MessageBeep(MB_OK);
break;
case FILE_MENU_NEW:
break;
case ID_GO:
{
//Work in progress
wchar_t usernameInput[100];
wchar_t passwordInput[100];
GetWindowTextW(usernameText,usernameInput,100);
GetWindowTextW(passwordText,passwordInput,100);
}
break;
}
case BUTTON_CALCULATOR:
MessageBeep(MB_OK);
CreateWindowW(L"calculatorClass",L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,NULL,NULL,NULL,NULL);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}
但是,更重要的是,"calculatorClass"
window class 没有调用 RegisterClassW()
,例如:
WNDCLASSW wc = {0};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"calculatorClass";
wc.lpfnWndProc = CalculatorWindowProcedure;
RegisterClassW(&wc)
您如何期望 CreateWindowW()
为它不知道的 class 创建一个 window?您的代码也没有检查 CreateWindowW()
调用是否失败,例如:
hCalcWnd = CreateWindowW(L"calculatorClass",L"Calculator", WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,NULL,NULL,NULL,NULL);
if (!hCalcWnd)
{
DWORD err = GetLastError(); // ERROR_CLASS_DOES_NOT_EXIST, etc...
...
}
附带说明一下,您没有为 File|New
子菜单上的 "Note"
项目分配 ID。为了与 File
菜单项保持一致,您应该考虑将 BUTTON_CALCULATOR
重命名为 TOOL_MENU_CALCULATOR
之类的名称。也许将 ID_GO
重命名为 BUTTON_GO
.