如何知道在 Win32 中选择的菜单项 API

How to know selected menu item in Win32 API

在 window API 中,我有一个弹出菜单,其中分别包含 3 个项目 "Line"、"Circle" 和 "Exit"。

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

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);
}

我想做的是,基于 selected 菜单项(线,圆,...)我执行特定的代码段,这也取决于从用户那里获得鼠标点击(WM_LBUTTONDOWN).

例如: 如果用户 selected "Line",我应该取两个点来画那条线。

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

  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);
}