菜单按钮触发另一个 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.