Win32 Menu bitmaps
-
Using an ImageList to load 16 x 16 bitmaps into a toolbar I've been trying to use the bitmaps from that same ImageList for corresponding menu items but I can't get rid of a whiteness around the images. The main code block code below gives the best I can get. Though I can use a
IMAGELISTDRAWPARAMS
setting theilDrawParams.rgbBk = GetSysColor(COLOR_MENU)
and usingImageList_DrawIndirect
which does get rid of the whiteness though the background is then wrong again if the menu item is highlighted - this also seems to be missing the point when is seems the bitmaps can supposedly be drawn transparently anyway. Any suggestions appreciated.// Get a menu handle for the one to have an image added to it HMENU hMenuMain = GetMenu(hWnd); HMENU hTestMenu = GetSubMenu(hMenuMain, PORT\_MENU\_ID); // Load the image i.e. a bitmap 'strip' that is actually a number of bitmaps HIMAGELIST hImageList = ::ImageList\_LoadImage(hInst, MAKEINTRESOURCE(IDB\_BITMAP1), 16, 0, RGB(255,0,255), IMAGE\_BITMAP, LR\_SHARED | LR\_LOADTRANSPARENT); // Get DC for Window client area HDC hDCWindow = ::GetDC(hWnd); // and create a compatibles DC im memory HDC hDCDest = CreateCompatibleDC(hDCWindow); // Create a bitmap compatible with the device associated with the DC HBITMAP hComapatBitmap = CreateCompatibleBitmap(hDCWindow, 16, 16); // Select the destination bitmap into the DC HGDIOBJ hOldDestBmp = SelectObject(hDCDest, hComapatBitmap); // Bitmap is already selected into a screen-compatible device context by the image list BOOL bDrawn = ImageList\_DrawEx(hImageList, 1, hDCDest, 0, 0, 16, 16, RGB(255, 0, 255), CLR\_NONE , ILD\_TRANSPARENT); // Select back old object back in retrieving returned drawn bitmap HBITMAP hRetrievedBitmap = (HBITMAP)::SelectObject(hDCDest, hOldDestBmp); // as used CreateCompatibleDC(...) must delete it ::DeleteDC(hDCDest); // as used GetDc must release it ::ReleaseDC(hWnd, hDCWindow); // Create a structure that describes the change to make to the menu item MENUITEMINFO MenuItemInfo; ::SecureZeroMemory(&MenuItemInfo, sizeof(MENUITEMINFO)); MenuItemInfo.cbSize = sizeof(MENUITEMINFO); MenuItemInfo.fMask = MIIM\_BITMAP; MenuItemInfo.hbmpItem = hRetrievedBitmap; // Make the change ::SetMenuItemInfo(hTestMenu, ID\_PORT\_E
-
Using an ImageList to load 16 x 16 bitmaps into a toolbar I've been trying to use the bitmaps from that same ImageList for corresponding menu items but I can't get rid of a whiteness around the images. The main code block code below gives the best I can get. Though I can use a
IMAGELISTDRAWPARAMS
setting theilDrawParams.rgbBk = GetSysColor(COLOR_MENU)
and usingImageList_DrawIndirect
which does get rid of the whiteness though the background is then wrong again if the menu item is highlighted - this also seems to be missing the point when is seems the bitmaps can supposedly be drawn transparently anyway. Any suggestions appreciated.// Get a menu handle for the one to have an image added to it HMENU hMenuMain = GetMenu(hWnd); HMENU hTestMenu = GetSubMenu(hMenuMain, PORT\_MENU\_ID); // Load the image i.e. a bitmap 'strip' that is actually a number of bitmaps HIMAGELIST hImageList = ::ImageList\_LoadImage(hInst, MAKEINTRESOURCE(IDB\_BITMAP1), 16, 0, RGB(255,0,255), IMAGE\_BITMAP, LR\_SHARED | LR\_LOADTRANSPARENT); // Get DC for Window client area HDC hDCWindow = ::GetDC(hWnd); // and create a compatibles DC im memory HDC hDCDest = CreateCompatibleDC(hDCWindow); // Create a bitmap compatible with the device associated with the DC HBITMAP hComapatBitmap = CreateCompatibleBitmap(hDCWindow, 16, 16); // Select the destination bitmap into the DC HGDIOBJ hOldDestBmp = SelectObject(hDCDest, hComapatBitmap); // Bitmap is already selected into a screen-compatible device context by the image list BOOL bDrawn = ImageList\_DrawEx(hImageList, 1, hDCDest, 0, 0, 16, 16, RGB(255, 0, 255), CLR\_NONE , ILD\_TRANSPARENT); // Select back old object back in retrieving returned drawn bitmap HBITMAP hRetrievedBitmap = (HBITMAP)::SelectObject(hDCDest, hOldDestBmp); // as used CreateCompatibleDC(...) must delete it ::DeleteDC(hDCDest); // as used GetDc must release it ::ReleaseDC(hWnd, hDCWindow); // Create a structure that describes the change to make to the menu item MENUITEMINFO MenuItemInfo; ::SecureZeroMemory(&MenuItemInfo, sizeof(MENUITEMINFO)); MenuItemInfo.cbSize = sizeof(MENUITEMINFO); MenuItemInfo.fMask = MIIM\_BITMAP; MenuItemInfo.hbmpItem = hRetrievedBitmap; // Make the change ::SetMenuItemInfo(hTestMenu, ID\_PORT\_E
-
Using an ImageList to load 16 x 16 bitmaps into a toolbar I've been trying to use the bitmaps from that same ImageList for corresponding menu items but I can't get rid of a whiteness around the images. The main code block code below gives the best I can get. Though I can use a
IMAGELISTDRAWPARAMS
setting theilDrawParams.rgbBk = GetSysColor(COLOR_MENU)
and usingImageList_DrawIndirect
which does get rid of the whiteness though the background is then wrong again if the menu item is highlighted - this also seems to be missing the point when is seems the bitmaps can supposedly be drawn transparently anyway. Any suggestions appreciated.// Get a menu handle for the one to have an image added to it HMENU hMenuMain = GetMenu(hWnd); HMENU hTestMenu = GetSubMenu(hMenuMain, PORT\_MENU\_ID); // Load the image i.e. a bitmap 'strip' that is actually a number of bitmaps HIMAGELIST hImageList = ::ImageList\_LoadImage(hInst, MAKEINTRESOURCE(IDB\_BITMAP1), 16, 0, RGB(255,0,255), IMAGE\_BITMAP, LR\_SHARED | LR\_LOADTRANSPARENT); // Get DC for Window client area HDC hDCWindow = ::GetDC(hWnd); // and create a compatibles DC im memory HDC hDCDest = CreateCompatibleDC(hDCWindow); // Create a bitmap compatible with the device associated with the DC HBITMAP hComapatBitmap = CreateCompatibleBitmap(hDCWindow, 16, 16); // Select the destination bitmap into the DC HGDIOBJ hOldDestBmp = SelectObject(hDCDest, hComapatBitmap); // Bitmap is already selected into a screen-compatible device context by the image list BOOL bDrawn = ImageList\_DrawEx(hImageList, 1, hDCDest, 0, 0, 16, 16, RGB(255, 0, 255), CLR\_NONE , ILD\_TRANSPARENT); // Select back old object back in retrieving returned drawn bitmap HBITMAP hRetrievedBitmap = (HBITMAP)::SelectObject(hDCDest, hOldDestBmp); // as used CreateCompatibleDC(...) must delete it ::DeleteDC(hDCDest); // as used GetDc must release it ::ReleaseDC(hWnd, hDCWindow); // Create a structure that describes the change to make to the menu item MENUITEMINFO MenuItemInfo; ::SecureZeroMemory(&MenuItemInfo, sizeof(MENUITEMINFO)); MenuItemInfo.cbSize = sizeof(MENUITEMINFO); MenuItemInfo.fMask = MIIM\_BITMAP; MenuItemInfo.hbmpItem = hRetrievedBitmap; // Make the change ::SetMenuItemInfo(hTestMenu, ID\_PORT\_E
I've never found a good solution to this problem. Maybe the HBMMENU_CALLBACK of Vista solves this (I havent tried it) but even in that case it would push up the minimum OS version requirement of your program without any particular reason. I've solved this problem a few times by using ownerdraw menu items but in that case you have to take care a lot of things even if you ignore the look and feel of the OS: like font sizes, underlining the hotkeys in menu item text... Customizing menu items and rawing their icons nicely is a pain in the ass. I would go with
ilDrawParams.rgbBk = GetSysColor(COLOR_MENU)
. It is not perfect but I wouldn't invest time in owner draw items again for a small cosmetic bug. -
I've never found a good solution to this problem. Maybe the HBMMENU_CALLBACK of Vista solves this (I havent tried it) but even in that case it would push up the minimum OS version requirement of your program without any particular reason. I've solved this problem a few times by using ownerdraw menu items but in that case you have to take care a lot of things even if you ignore the look and feel of the OS: like font sizes, underlining the hotkeys in menu item text... Customizing menu items and rawing their icons nicely is a pain in the ass. I would go with
ilDrawParams.rgbBk = GetSysColor(COLOR_MENU)
. It is not perfect but I wouldn't invest time in owner draw items again for a small cosmetic bug.The problem seems to be that the Menu background as obtained by getting
MENUINFO.hbrBack
isn't the same colour as the menus. I filled my bitmaps that go on the menus with that colour without any icons to see if it all matched. It doesn't, I can see white squares where the icons go against the light blue/grey of the menu (on Windows 8) That white, as seen behind the drawn bitmaps, is presumably what I was trying to remove. I think I'll take your advice leave it as it is. Thanks. -
The bitmap needs to contain some indication of transparent background to avoid this problem. I cannot remember exactly how it is identified, but I have a feeling it is some "key" pixel. MSDN or Google may have more information.
Use the best guess
Richard, Thanks for the hint, but (as explained below) the problem seems to be with the obtained menu background (white)not being the same colour as the menu (light blue/grey). Thanks anyway.
-
The problem seems to be that the Menu background as obtained by getting
MENUINFO.hbrBack
isn't the same colour as the menus. I filled my bitmaps that go on the menus with that colour without any icons to see if it all matched. It doesn't, I can see white squares where the icons go against the light blue/grey of the menu (on Windows 8) That white, as seen behind the drawn bitmaps, is presumably what I was trying to remove. I think I'll take your advice leave it as it is. Thanks.I'm still stuck on win7 but I guess what you mean. Since WinXP there are several window managers (like aero, xp-style, old-school,...) and some of these are using extra colors besides the old-school window manager for which the old API was engineered. Sometimes the api lies to your program depending on windows version compatibility settings and the manifest you put into your program. I wouldn't be surprised if there were some fancy APIs to query the REAL colors in another way or with different constants from a newer SDK but I avoided making headaches for myself by polishing GUIs with WinAPI in the last few years... :-) I guess you have better things to do and customizing the menus is one particular thing that really sucks. In my opinion most of the winapi controls, especially the older ones (including menus) are not good candidates for customization. Things could be worse only if you wanted to customize the menu borders: I've seen code that handled undocumented mouse messages and installed cbt hooks - made me sick and I always started vomiting while reading it... Once I was dreaming about creating a gui skinner lib but I got bored of it halfway when I got to know the sad truth and the mountain of hacks involved...
-
I've never found a good solution to this problem. Maybe the HBMMENU_CALLBACK of Vista solves this (I havent tried it) but even in that case it would push up the minimum OS version requirement of your program without any particular reason. I've solved this problem a few times by using ownerdraw menu items but in that case you have to take care a lot of things even if you ignore the look and feel of the OS: like font sizes, underlining the hotkeys in menu item text... Customizing menu items and rawing their icons nicely is a pain in the ass. I would go with
ilDrawParams.rgbBk = GetSysColor(COLOR_MENU)
. It is not perfect but I wouldn't invest time in owner draw items again for a small cosmetic bug.Read the MSDN stuff again and found I should have been using
GetSysColorBrush(COLOR_MENU);
rather then theGetSysColor(COLOR_MENU);
I was using which apparently 'returns a cached brush, instead of allocating a new one'. This now does the correct menu background colour. Could explain whyGetSysColor(COLOR_MENU);
worked yesterday and not today. -
Read the MSDN stuff again and found I should have been using
GetSysColorBrush(COLOR_MENU);
rather then theGetSysColor(COLOR_MENU);
I was using which apparently 'returns a cached brush, instead of allocating a new one'. This now does the correct menu background colour. Could explain whyGetSysColor(COLOR_MENU);
worked yesterday and not today.Thanks for the info! We learn something new every day... :-)