菜单按钮触发另一个窗口

Posted

技术标签:

【中文标题】菜单按钮触发另一个窗口【英文标题】:Menu button triggering another window 【发布时间】:2020-01-13 20:11:21 【问题描述】:

我是 C++ 新手,已经开始了解 Win32 GUI。我试图让一个子菜单按钮打开一个窗口,该窗口将显示一个计算器窗口,但是我似乎无法通过做逻辑的事情来弄清楚它,我在网上找不到任何有用的东西。请帮忙! 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);




【问题讨论】:

您到底遇到了什么问题?目前还不清楚真正的问题是什么。 正如描述中所述,我试图在单击菜单按钮时打开一个窗口 【参考方案1】:

您的WM_COMMAND 处理程序检查WPARAM 值不正确。

WPARAM 值的 LOWORD 包含正在发送 WM_COMMAND 消息的项目的 ID,HIWORD 包含通知代码,例如BN_CLICKED 等。您忽略了@987654327 @ 完全地。您的switch(wp) 语句仅适用于HIWORD 为0 的菜单项,但不适用于HIWORD 不为0 的按钮单击等操作。您的ID_GO 控件是一个按钮,而不是菜单项,因此 wp 参数永远不会完全是 ID_GO 用于您的 switch(wp) 语句来查找 case

至少,您需要将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" 窗口类没有调用 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() 为它不知道的类创建一个窗口?您的代码也没有检查 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...
    ...


附带说明,您没有为"Note" 子菜单上的"Note" 项目分配ID。为了与您的File 菜单项保持一致,您应该考虑将BUTTON_CALCULATOR 重命名为TOOL_MENU_CALCULATOR。并且可能将ID_GO 重命名为BUTTON_GO

【讨论】:

感谢您的回答,但我认为这不能解决问题。我的 ID_GO 不是我试图打开新窗口的按钮。我正在尝试获取菜单按钮,该按钮被归类为 (BUTTON_CALCULATOR) 以触发窗口。我尝试了建议的 HIWORD 和 LOWORD,但它只是给了我错误。我知道这对于一个不熟悉 c++ 但我迷路的人来说可能是显而易见的。 p.s 谢谢你的旁注。 究竟是什么错误?请更具体。您是否使用调试器单步执行代码以确保收到 WM_COMMAND 并且 switch/case 语句正在执行您所期望的操作?您在哪里注册 "calculatorClass" 窗口类?您的代码未检查 CreateWindowW() 调用是否失败。 第一个是“duplicate case value”把我带到了“case BN_CLICKED:” 没关系,我没有意识到 BN_CLICKED 被定义为 0。不过,在检查 ID 时,您仍然应该在 switch (LOWORD(wp)) 中使用 LOWORD。我更新了我的答案

以上是关于菜单按钮触发另一个窗口的主要内容,如果未能解决你的问题,请参考以下文章

Pyside2 QAction 会自动触发一次,但不会在用户单击菜单时触发

Web浏览器常用事件

java 如何隔一段时间自动重复触发一个按钮动作?

在多个组件中触发相同的功能

怎样通过一个按钮触发另一个按钮点击

从下拉列表中触发时,Bootstrap-4 模态不显示