代码之家  ›  专栏  ›  技术社区  ›  Viole Grace

如何创建带有图标的Win32 API菜单项?

  •  0
  • Viole Grace  · 技术社区  · 2 年前

    我正在尝试使用Win32 API将图标添加到Windows应用程序中的菜单项,但图标未显示。我已经按照Win32 API文档中的说明进行了操作,但它仍然不起作用。有人能帮我解决这个问题吗?

    HMENU createContextMenu(HWND hwnd, HINSTANCE hInstance) {
        HMENU hMenu = CreatePopupMenu();
        if (hMenu) {
            AppendMenu(hMenu, MF_STRING, IDM_APP_ABOUT, "&About");
            AppendMenu(hMenu, MF_SEPARATOR, (UINT_PTR)-1, NULL);
            AppendMenu(hMenu, MF_STRING, IDM_APP_EXIT, "&Exit");
    
            // Assuming you have an icon resource named ICON_MENU_EXIT
            HICON hIconExit = LoadIcon(hInstance, MAKEINTRESOURCE(ICON_MENU_EXIT));
            if (hIconExit) {
                MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) };
                menuItemInfo.fMask = MIIM_BITMAP;
                menuItemInfo.hbmpItem = (HBITMAP)CopyImage(hIconExit, IMAGE_ICON, 0, 0, LR_COPYFROMRESOURCE);
                SetMenuItemInfo(hMenu, IDM_APP_EXIT, FALSE, &menuItemInfo);
                DestroyIcon(hIconExit); // Destroy the icon only if setting the image was successful
            }
        }
        return hMenu;
    }
    
    case WM_USER_TRAYICON:
            if (lParam == WM_LBUTTONDBLCLK) {
                ShowWindow(hwnd, SW_SHOW);
            } else if (lParam == WM_RBUTTONUP) {
                POINT trayPos;
                GetCursorPos(&trayPos);
                HMENU hMenu = createContextMenu(hwnd,hInstance);
                SetForegroundWindow(hwnd); // Menjamin menu bekerja dengan benar
                UINT clicked = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_NONOTIFY, trayPos.x, trayPos.y, 0, hwnd, NULL);
                if (clicked == IDM_APP_EXIT) {
                    PostQuitMessage(0);
                }
                DestroyMenu(hMenu); // Hancurkan menu setelah digunakan
            }
            break;
    

    我尝试使用LoadIcon函数从资源加载图标,并使用SetMenuItemInfo或SetMenuItemsBitmaps将其设置为菜单项。我希望在显示菜单时,图标会出现在菜单项“退出”旁边。然而,尽管遵循了Win32 API文档中概述的步骤,图标仍然没有显示。

    1 回复  |  直到 2 年前
        1
  •  1
  •   Remy Lebeau    2 年前

    HICON 和一个 HBITMAP 是完全不同的类型。你不能使用 HICON 直接与 SetMenuItemInfo() SetMenuItemBitmaps() .

    您必须:

    1. 将资源类型更改为 BITMAP ,然后使用 LoadBitmap() LoadImage(IMAGE_BITMAP) 将其加载为 HBITMAP .

    2. 和一个呆在一起 ICON 资源,将其加载为 HICON 就像你一样,然后:

      a.将其复制到单独的 HBITMAP 然后您可以将其分配给您的菜单项。看见 How to convert HICON to HBITMAP in VC++?

      b Owner-draw the menu item ,处理 WM_DRAWITEM 留言,这样你就可以画你的 HICON HDC 的菜单使用 DrawIcon() .

        2
  •  0
  •   Viole Grace    2 年前
    HMENU createContextMenu(HWND hwnd, HINSTANCE hInstance) {
    HMENU hMenu = CreatePopupMenu();
    if (hMenu) {
        AppendMenu(hMenu, MF_STRING, IDM_APP_ABOUT, "&About");
        AppendMenu(hMenu, MF_SEPARATOR, (UINT_PTR)-1, NULL);
        AppendMenu(hMenu, MF_STRING, IDM_APP_EXIT, "&Exit");
    
        HICON hMenuExitIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ICON_MENU_EXIT));
        if (hMenuExitIcon) {
            // Create a compatible DC
            HDC hdc = GetDC(hwnd);
            HDC hdcMem = CreateCompatibleDC(hdc);
    
            // Get the size of the icon
            ICONINFO iconInfo;
            GetIconInfo(hMenuExitIcon, &iconInfo);
            BITMAP bmp;
            GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp);
    
            // Create a bitmap compatible with the DC
            HBITMAP hBitmap = CreateCompatibleBitmap(hdc, bmp.bmWidth, bmp.bmHeight);
    
            // Select the bitmap into the memory DC
            HBITMAP hOldBitmap = SelectObject(hdcMem, hBitmap);
    
            // Draw the icon onto the bitmap
            DrawIconEx(hdcMem, 0, 0, hMenuExitIcon, bmp.bmWidth, bmp.bmHeight, 0, NULL, DI_NORMAL);
    
            // Set the bitmap as the item's bitmap
            MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) };
            menuItemInfo.fMask = MIIM_BITMAP;
            menuItemInfo.hbmpItem = hBitmap;
            SetMenuItemInfo(hMenu, IDM_APP_EXIT, FALSE, &menuItemInfo);
    
            // Clean up
            SelectObject(hdcMem, hOldBitmap);
            DeleteDC(hdcMem);
            ReleaseDC(hwnd, hdc);
            DestroyIcon(hMenuExitIcon);
        } else {
            MessageBox(NULL, "Failed to load icon for exit menu item.", "Error", MB_OK | MB_ICONERROR);
        }
    }
    return hMenu;
    

    }

    现在它开始工作了

        3
  •  0
  •   Adrian McCarthy    2 年前

    这些都是旧的、令人困惑的API,我的记忆很模糊,但我认为有几件事正在发生。

    1. 如果您想要字符串旁边的图标,那么您需要 MIIM_CHECKMARKS 并设置 hbmpChecked hbmpUnchecked 领域。当您使用 MIIM_BITMAP ,也就是说你想要一个图标 而不是 字符串。

    2. 您需要使用实际的位图,而不是图标。(在WinAPI中,有些地方位图、图标和光标可以互换使用,但我不认为这是其中之一。)为了使位图具有显示菜单颜色的“透明”部分,您需要使用8位颜色位图,并用 LoadImage (使用 LR_LOADTRANSPARENT 而且可能 LR_LOADMAP3DCOLORS LoadIcon .

    在你开始工作之前,我建议你在调试器中逐步完成这段代码,并检查所有的返回值。