On Sat, 29 Mar 2025 20:30:15 GMT, Phil Race <p...@openjdk.org> wrote:
> > ``` > > mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID | MIIM_BITMAP | > > MIIM_CHECKMARKS; > > ``` > > Per > https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-menuiteminfoa > > The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined with > one another. (nb MIIM is the replacement name for MFT but the same applies) > > I suspect you mean to be setting HBITMAP hbmpChecked; and/or HBITMAP > hbmpUnchecked; > > not HBITMAP hbmpItem; which is used to display a bitmap instead of a text > string label. > > Also you aren't clearing the fMask / resetting it when using the entries > without a bitmap I have no idea how much all of this can confuse the GDI API. Here's the new program without setting MFT_BITMAP and MFT_STRING together and using hbmpChecked #include <windows.h> #include <string> #define IDM_RADIO1 1001 #define IDM_RADIO2 1002 #define IDM_RADIO3 1003 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("RadioMenuDemo"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; RegisterClass(&wndclass); hwnd = CreateWindow(szAppName, TEXT("Radio Menu Demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HMENU hMainMenu, hRadioSubMenu; switch (message) { case WM_CREATE: { // Create main menu hMainMenu = CreateMenu(); hRadioSubMenu = CreatePopupMenu(); // Configure menu items using MENUITEMINFO MENUITEMINFO mii = { 0 }; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID | MIIM_CHECKMARKS; // | MIIM_BITMAP; // First radio item mii.fType = MFT_RADIOCHECK; std::wstring wstr1 = L"Radio Option 1"; LPWSTR lp1 = (LPWSTR)wstr1.c_str(); mii.dwTypeData = lp1; mii.cch = (UINT)strlen((const char *)lp1); mii.wID = IDM_RADIO1; mii.fState = MFS_CHECKED; HDC hdc = GetDC(hwnd); HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 16, 16); HDC memDC = CreateCompatibleDC(hdc); //HGDIOBJ oldObj = SelectObject(memDC, hBitmap); HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0)); RECT rect = { 0, 0, 16, 16 }; FillRect(memDC, &rect, hBrush); mii.hbmpChecked = hBitmap; //mii.hbmpItem = hBitmap; InsertMenuItem(hRadioSubMenu, 0, TRUE, &mii); // Second radio item std::wstring wstr2 = L"Radio Option 2"; LPWSTR lp2 = (LPWSTR)wstr2.c_str(); mii.dwTypeData = lp2; mii.cch = (UINT)strlen((const char *)lp2); mii.wID = IDM_RADIO2; mii.hbmpChecked = hBitmap; InsertMenuItem(hRadioSubMenu, 1, TRUE, &mii); // Third radio item std::wstring wstr3 = L"Radio Option 3"; LPWSTR lp3 = (LPWSTR)wstr3.c_str(); memset((void *) & mii, 0, sizeof(mii)); mii.cbSize = sizeof(MENUITEMINFO); mii.fType = MFT_RADIOCHECK; mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID | MIIM_CHECKMARKS; mii.dwTypeData = lp3; mii.cch = (UINT)strlen((const char *)lp3); mii.wID = IDM_RADIO3; mii.hbmpChecked = NULL; //mii.hbmpItem = NULL; InsertMenuItem(hRadioSubMenu, 2, TRUE, &mii); // Add submenu to main menu AppendMenu(hMainMenu, MF_POPUP, (UINT_PTR)hRadioSubMenu, L"Options"); SetMenu(hwnd, hMainMenu); // Set initial checked item using CheckMenuRadioItem CheckMenuRadioItem(hRadioSubMenu, IDM_RADIO1, IDM_RADIO3, // Group range IDM_RADIO1, // Initial selection MF_BYCOMMAND); // Identifier type return 0; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_RADIO1: case IDM_RADIO2: case IDM_RADIO3: // Update radio selection CheckMenuRadioItem(hRadioSubMenu, IDM_RADIO1, IDM_RADIO3, LOWORD(wParam), MF_BYCOMMAND); break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } It seems in windows 11 with this program, the imageicon cannot be clubbed with radiobullet/checkmark if BITMAP/STRING cannot be together so it will look like if RadioButton 1 is selected with icon (ie BITMAP)  if RadioButton 3 is selected without icon (ie BITMAP set to NULL)  We can make changes in JDK to only draw imageicon if menuitem is selected which will let user distinguish between selected/unselected menuitem ------------- PR Comment: https://git.openjdk.org/jdk/pull/23324#issuecomment-2820134416