【问题标题】:How to know selected menu item in Win32 API如何知道 Win32 API 中的选定菜单项
【发布时间】:2017-04-20 00:26:38
【问题描述】:

在窗口 API 中,我有一个弹出菜单,其中分别包含 3 项“Line”、“Circle”和“Exit”。

我的程序是让用户选择要绘制的形状,然后获取点、参数(即线的起点和终点,...)。这是我目前编写的部分代码。

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam) {

    HMENU hMenu;
    POINT point;
    HDC hdc;
    hdc = GetDC(hwnd);
    static int x1, y1,x2,y2,count = 0;
    switch (msg) {

    case WM_LBUTTONDOWN:
        count++;
        if (count == 1)
        {
            x1 = LOWORD(lParam);
            y1 = HIWORD(lParam);
        }
        else
        {
            x2 = LOWORD(lParam);
            y2 = HIWORD(lParam);

            // I think the problem goes here, it never execute else part 
            //even if global_ID ==2, Am I missing something?

            if (global_ID == 1)//Line
            {DirectMethod(hdc, x1, y1, x2, y2, RGB(0, 0, 0));}
            else if (global_ID == 2)//Circle
            {Ellipse(hdc, x1, y1, x2, y2);}
            count = 0;
        }
    case WM_COMMAND:

        switch (LOWORD(wParam)) {
        case IDM_FILE_LINE:
            global_ID = 1;
            break;
        case IDM_FILE_CIRCLE:
            global_ID = 2;//Global Variable
            break;

        case IDM_FILE_QUIT:

            SendMessage(hwnd, WM_CLOSE, 0, 0);
            break;
        }

        break;

    case WM_RBUTTONUP:

        point.x = LOWORD(lParam);
        point.y = HIWORD(lParam);

        hMenu = CreatePopupMenu();
        ClientToScreen(hwnd, &point);

        AppendMenuW(hMenu, MF_STRING, IDM_FILE_LINE, L"&line");
        AppendMenuW(hMenu, MF_STRING, IDM_FILE_CIRCLE, L"&Circle");
        AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
        AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");

        TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd, NULL);
        DestroyMenu(hMenu);
        break;

    case WM_DESTROY:

        PostQuitMessage(0);
        break;
    }

    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

我想要做的是,基于选定的菜单项(Line、Circle、...)我执行特定的代码段,这也取决于从用户获得鼠标点击 (WM_LBUTTONDOWN)。

例如: 如果用户选择“线”,我应该用两点来画那条线。

【问题讨论】:

  • 您的实际问题是什么?您的代码已经在检测选择了哪个菜单项,这是由 WM_COMMAND 消息报告的。那么,您的问题只是收集用户输入?例如,您可以让WM_COMMAND 处理程序设置一个标志,指示所需坐标的编号,然后让您的WM_LBUTTONDOWN/UP 处理程序保存坐标,直到达到该编号。您遇到的实际问题是什么?
  • @RemyLebeau 问题是当一个菜单项被选中时,我更改“global_ID”值以知道选择了哪个菜单项,但在“WM_LBUTTONDOWN”内它“总是”执行 if 语句,从不执行 else部分,我已经调试了该代码,并且“global_ID”设置为“2”。我的意思是它假设执行“else”部分,但它总是执行“if”部分
  • 您应该在问题中说明这些细节。鉴于global_ID 不是WndProc() 的本地变量,您所描述的内容应该是不可能的,因此WM_COMMAND 分配的任何值都将传递给后续的WM_LBUTTONDOWN。但是,您的代码中存在逻辑漏洞:1)即使您不应该计数鼠标点击,您也会计数。当您设置global_ID 时,您不会将count 重置为0; 2) 当global_ID 不是 1 或 2 时,WM_LBUTTONDOWN 根本不应该做任何事情; 3)你没有在调用DirectMethod()/Ellipse()后重置global_ID...
  • ... 和 4) 您的 WM_LBUTTONDOWN 缺少必需的 break 语句,因此每条鼠标按下消息都会传递到 WM_COMMAND 代码。
  • 您在WM_LBUTTONDOWN 处理程序末尾缺少break;

标签: c++ windows user-interface winapi win32gui


【解决方案1】:

您的代码中存在逻辑漏洞:

  1. 即使您不应该计算鼠标点击次数,您也在计算。当您的WM_COMMAND 处理程序设置global_ID 时,您不会同时将count 重置为0,因此后续单击可能最终会跳过x1/y1 的分配,因为count 可能已经是> 0 .

  2. global_ID 不是 1 或 2 时,您的 WM_LBUTTONDOWN 处理程序根本不应该做任何事情。

  3. 在调用DirectMethod()/Ellipse() 之后,您并没有重置global_ID,因此WM_LBUTTONDOWN 将继续无休止地计算点击次数,并在每次点击时执行其绘图。

  4. 您的WM_LBUTTONDOWN 缺少必需的break 语句,因此每条WM_LBUTTONDOWN 消息都将落入WM_COMMAND 代码。

试试这个:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int x1, y1, x2, y2, count = 0, global_ID = 0;

    switch (msg)
    {
        case WM_LBUTTONDOWN:
        {
            switch (global_ID)
            {
                case 1: //Line
                case 2: //Circle
                {
                    ++count;
                    if (count == 1)
                    {
                        x1 = GET_X_LPARAM(lParam);
                        y1 = GET_Y_LPARAM(lParam);
                    }
                    else
                    {
                        x2 = GET_X_LPARAM(lParam);
                        y2 = GET_Y_LPARAM(lParam);

                        HDC hdc = GetDC(hwnd);

                        if (global_ID == 1) {
                            DirectMethod(hdc, x1, y1, x2, y2, RGB(0, 0, 0));
                        }
                        else {
                            Ellipse(hdc, x1, y1, x2, y2);
                        }

                        ReleaseDC(hwnd, hdc);

                        global_ID = 0;
                    }

                    break;
                }
            }

            break;
        }

        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case IDM_FILE_LINE:
                    global_ID = 1;
                    count = 0;
                    break;

                case IDM_FILE_CIRCLE:
                    global_ID = 2;
                    count = 0;
                    break;

                case IDM_FILE_QUIT:
                    SendMessage(hwnd, WM_CLOSE, 0, 0);
                    break;
            }

            break;
        }

        case WM_RBUTTONUP:
        {
            POINT point;
            point.x = GET_X_LPARAM(lParam);
            point.y = GET_Y_LPARAM(lParam);
            ClientToScreen(hwnd, &point);

            HMENU hMenu = CreatePopupMenu();        
            AppendMenuW(hMenu, MF_STRING, IDM_FILE_LINE, L"&line");
            AppendMenuW(hMenu, MF_STRING, IDM_FILE_CIRCLE, L"&Circle");
            AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
            AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
            TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd, NULL);
            DestroyMenu(hMenu);

            break;
        }

        case WM_DESTROY:
        {
            PostQuitMessage(0);
            break;
        }
    }

    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-12
    • 2021-07-01
    • 2011-12-30
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多