CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 24

Thread: Applying menu item images

  1. #1
    Join Date
    Mar 2002
    Location
    Chicago, IL
    Posts
    255

    Applying menu item images

    Hi all -

    I'm trying to add images to a CMenu, and I'm trying to do it at first without owner-drawn menus or making use of the new MFC Feature Pack. I see that the MENUITEMINFO structure has an 'hbmpItem' field which I was thinking could be used. In my case, I have an icon file that contains 16x16, 24x24, 32x32, and 48x48 size images. Is there a way I can take this icon file, extract the 16x16 image, and make it the image next to the text on my menu using the 'hbmpItemp' field? I tried making use of image lists at first, but that didn't work:

    In OnCreate of my frame:

    Code:
        VERIFY( m_ilMenu16.Create( 16, 16, ILC_COLOR | ILC_MASK, 0, 4 ) );
    Where 'm_ilMenu16' is a CImageList member. Then later:

    Code:
        int nImageIdx = m_ilMenu16.Add( hIcon );
    
        IMAGEINFO ii;
        m_ilMenu16.GetImageInfo( nImageIdx, &ii );
    
        MENUITEMINFO mii;
        mii.cbSize = sizeof( MENUITEMINFO );
        mii.fMask = MIIM_BITMAP;
        mii.hbmpItem = ii.hbmImage;
        m_pMenu->SetMenuItemInfo( m_pMenu->GetMenuItemCount() - 1, &mii, TRUE );
    Any ideas? Thanks in advance.

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    19,734

    Re: Applying menu item images

    1. Convert icon to bitmap:
    http://www.programmersheaven.com/mb/...con---hbitmap/
    http://www.google.com/search?num=20&...=&oq=&gs_rfai=

    2. You could use CMenu::SetMenuItemBitmaps directly.

    3. Note that these bitmaps are used for the checked or unchecked state of menu item
    Victor Nijegorodov

  3. #3
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Applying menu item images

    Note that if you take bitmaps from the IMAGEINFO struct they will not contain the background of your menu and will appear black. So in that case you'd need to replace it with the background color of your menu. Moreover, if those icons contain alpha channel, Windows GDI functions won't know how to handle it and your bitmap will appear jagged and pixelated on the edges.
    IMO, I wouldn't mess with icons and go with bitmaps instead. That way you can load them with CreateMappedBitmap() and replace the background color, all in one call. The sacrifice in this is case is also alpha channel, but you can neglect it because your bitmaps will be relatively small.
    Last edited by ahmd; July 20th, 2010 at 05:05 AM.

  4. #4
    Join Date
    Mar 2002
    Location
    Chicago, IL
    Posts
    255

    Re: Applying menu item images

    Thank you both for your responses. I tried the route where I generate a bitmap from the icon, but didn't get the result I expected/wanted. My code is:

    Code:
    void CreateMenuBitmap( HICON hIcon, HBITMAP& hBitmap )
    {
        HDC hDC = ::GetDC( NULL );
        hBitmap = ::CreateCompatibleBitmap( hDC, 16, 16 );
    
        HDC hDCTemp = ::CreateCompatibleDC( hDC );
        ::ReleaseDC( NULL, hDC );
    
        HBITMAP hBitmapOld = ( HBITMAP ) ::SelectObject( hDCTemp, hBitmap );
        ::DrawIconEx( hDCTemp, 0, 0, hIcon, 16, 16, 0, ::GetSysColorBrush( COLOR_MENU ), DI_NORMAL );
        
        ::SelectObject( hDCTemp, hBitmapOld );
        ::DeleteDC( hDCTemp );
    }
    As an example, this code yields the image in the attached picture (the second one labeled "MFC menu"). In that same picture, the first image labeled "C# menu" is the result of using the same icon with .Net controls. I've also attached the icon using for this particular example (zipped up). It appears that the "MFC menu" is trying to use a scaled-down version of a larger 32-bit bitmap from the icon, whereas the "C# menu" appears to be using the correct 16x16 8-bit bitmap from the icon. Any thoughts on how I can extract a specific bitmap from the icon, namely in this case the 16x16 8-bit image?

    Also, I know using bitmaps in this case would be more ideal, however I writing a third-party component that receives icons from the client.

    Thanks in advance for your thoughts.

    - Steve
    Attached Images Attached Images  
    Attached Files Attached Files

  5. #5
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Applying menu item images

    First off, you don't force your own icon size into menu images. Instead you read the default menu bitmap size by using GetSystemMetrics and CXMENUCHECK and CYMENUCHECK. It may very for each OS.

    Secondly, the reason you see different images for the same icon file is due to the way it is loaded. You see, the file you attached has 8 different icon images in it and when you call an icon loading API it loads it up and gives you an HICON handle, that represents only one image. In your case you'd normally call LoadImage() with IMAGE_ICON and correct dimensions for an icon (that I gave above) to scale it up or down, or do the scaling yourself when the icon is loaded in the Device Context.

  6. #6
    Join Date
    Mar 2002
    Location
    Chicago, IL
    Posts
    255

    Re: Applying menu item images

    Thanks so much ahmd for your quick responses. I'll look into loading the correct sizes with LoadImage, although I'm confused why using the same HICON seems to work when I use a toolbar. I have a toolbar that I add the HICON to, and I allow the user to choose between three different sizes - Small (16x16), Medium (24x24), and Large (32x32). I create the toolbar and image lists:

    Code:
    int CMyFrame::OnCreate( LPCREATESTRUCT lpCreateStruct )
    {
        // ...
    
        if ( m_wndToolBar.CreateEx( this, TBSTYLE_FLAT, 
            WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_SIZE_FIXED | CBRS_FLYBY | CBRS_TOOLTIPS ) == FALSE )
        {
            return -1;
        }
    
        VERIFY( m_ilToolBar16.Create( 16, 16, ILC_COLOR32 | ILC_MASK, 0, 4 ) );
        VERIFY( m_ilToolBar24.Create( 24, 24, ILC_COLOR32 | ILC_MASK, 0, 4 ) );
        VERIFY( m_ilToolBar32.Create( 32, 32, ILC_COLOR32 | ILC_MASK, 0, 4 ) );
    
        SetToolbarSize( 24 );
        // ...
    }
    Set the initial size of the toolbar to 24:

    Code:
    BOOL CMyFrame::SetToolbarSize( int nSize )
    {
        CImageList* pImageList = NULL;
    
        switch ( nSize )
        {
        case 16: pImageList = &m_ilToolBar16; break;
        case 24: pImageList = &m_ilToolBar24; break;
        case 32: pImageList = &m_ilToolBar32; break;
        // Default to size 24 if the new size doesn't match any of the three.
        default: pImageList = &m_ilToolBar24; nSize = 24; break;
        }
    
        // If the desired toolbar size already matches what's being displayed,
        // then bail out.
        if ( m_nToolBarSize == nSize )
        {
            return FALSE;
        }
    
        m_nToolBarSize = nSize;
    
        m_wndToolBar.SetSizes( CSize( nSize + 7, nSize + 8 ), CSize( nSize, nSize ) );
        m_wndToolBar.GetToolBarCtrl().SetImageList( pImageList );
    
        RepositionBars( AFX_IDW_TOOLBAR, AFX_IDW_TOOLBAR, 0 );
    
        return TRUE;
    }
    And later add the HICON to the toolbar dynamically:

    Code:
    void CMyFrame::AddToolbarButton( UINT nCommandId, HICON hIcon )
    {
        int nImageIdx = -1;
        
        // A command id of zero implies a separator.
        if ( nCommandId != 0 )
        {
            ASSERT( hIcon != NULL );
            // ASSERT -> Should have a valid icon.
    
            nImageIdx = m_ilToolBar16.Add( hIcon );
    
            // Add the same icon to the other two toolbars and verify that the indexes
            // are the same.
            VERIFY( m_ilToolBar24.Add( hIcon ) == nImageIdx );
            VERIFY( m_ilToolBar32.Add( hIcon ) == nImageIdx );
        }
        else
        {
            ASSERT( hIcon == NULL );
            // ASSERT -> For separators, we shouldn't be passed icon handles.
        }
    
        TBBUTTON tbb;
        tbb.idCommand = nCommandId;
        tbb.iBitmap = nImageIdx;
        tbb.fsState = TBSTATE_ENABLED;
        tbb.fsStyle = ( ( nCommandId != 0 ) ? TBSTYLE_BUTTON : TBSTYLE_SEP );
        tbb.dwData = 0;
        tbb.iString = -1;
    
        m_wndToolBar.GetToolBarCtrl().AddButtons( 1, &tbb );
    }
    When I switch between the three available sizes via a menu item, the resulting images on the toolbar appear to be using the correct size bitmaps in the icon file - even though I use the same HICON for all three image lists. That's why I thought I could initially use a 16x16 image list for the menu. Can you explain that one to me, 'cause I don't get it!

    Also, you mentioned something about alpha channels with the icon images. I've noticed something too a little off with my toolbar images. I've attached a capture of this icon on two different toolbars. The top image has this icon on an MFC CToolbar in one of my apps, and the bottom image is the same icon on an MFC CToolbar in a different app I'm working on. I can't figure out why the shadow in the second image isn't that light gray color that I see in the first image. I build the toolbars the same. The app I'm currently working on isn't themed, but I wouldn't think this has anything to do with it. Any ideas?
    Attached Images Attached Images  

  7. #7
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Applying menu item images

    First off, you're not using image lists correctly. If you add your images through image lists, then load them into an image list and then specify their indexes for the toolbar. In your code you created an empty image list and then started adding icons to the toolbar. So redo this.

    Secondly, when you apply your HICON to various sizes of controls the original icon is resized within them. As I told you before, the size of the icon pointed by the HICON handle is determined at the time when you load it (with LoadIcon or LoadImage). Later on it is simply resized within your controls (buttons, toolbars, etc).

    And lastly, indeed your screenshots illustrate the concept of an alpha channel. The bottom one doesn't have it, thus you're losing transparency on that icon. As I told you many GDI functions will drop an alpha channel, so try to minimize your icon exposure to them, or work with the colors directly via a DIB section and RGBA values. (You have another option to go with GDI+.)

  8. #8
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Applying menu item images

    The way you did this in the old code is supported for the backward compatibility only. Back then Windows had no notion of transparency. Don't use that method now.

    Again, to add buttons to a toolbar, you first create an image list. Use CImageList class for that. You then maintain its copy throughout the life cycle of your toolbar. Then you can load your icons whith LoadImage and the correct icon size and add them to an image list using CImageList::Add method for an icon. When your image list is ready you set it for a toolbar: CToolBarCtrl::SetImageList and only after that you can begin adding buttons. So when you call CToolBarCtrl::AddButtons you specify an index of each image in the image list in the TBBUTTON::iBitmap member. In case you need to alter an image list later on, you can do so with the CImageList class methods and update your toolbar then.

    You technically don't need to worry about an alpha channel. When you use icons it is included internally (provided you made your icons this way, of course). All the latest icon editors (paid ones, for sure) provide means to save icons with transparency.

    Word of caution though: If you're using older versions of Visual Studio (up to 2003, I believe) the resource editor is not compatible with a newer icon format with alpha channel and it may not display them correctly, or at times even mess your icon file up. Even the latest version of Visual Studio 2008 still has some glitches about displaying and editing icons with transparency, so my advice is not to attempt to edit icons within the Visual Studio at all.

  9. #9
    Join Date
    Mar 2002
    Location
    Chicago, IL
    Posts
    255

    Re: Applying menu item images

    Well, I'm doing things in a slightly different order than what you suggest. And I even re-arranged some code to follow your flow, but in the end the result was the same.

    You said to create the image list, add the icons, set it in the toolbar, then add the buttons. I create the image list, set it (empty) in the toolbar, add an icon to the image list, then add a single button. Those last two steps happen for each component I discover at runtime.

    With the original code I posted, my toolbar is being generated correctly. The only problem is that the images on the toolbar buttons don't appear to have the correct transparency. I know these icons have this capability because they display as I would expect them to in a different application of mine - still using CToolBar and CImageList. I just can't for the life of me figure out why they don't in this new app.

    I don't want to keep taking up your time on this - you've helped me out a great deal and taught me a few things along the way. Thanks so much.

  10. #10
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Applying menu item images

    Listen, I keep repeating it over and over again -- the way icon is loaded defines how it will look when you display it. How do you load your icons, can you show the code?

  11. #11
    Join Date
    Mar 2002
    Location
    Chicago, IL
    Posts
    255

    Re: Applying menu item images

    I've created a bare-bones VS2008 sample app that makes a toolbar with 24x24 images. Note the icon has a black shadow when I believe that should be semi-transparent.
    Attached Files Attached Files

  12. #12
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Applying menu item images

    Quote Originally Posted by sjc View Post
    I've created a bare-bones VS2008 sample app that makes a toolbar with 24x24 images. Note the icon has a black shadow when I believe that should be semi-transparent.
    Listen, your project doesn't even compile. There's an H file missing. I don't have time for this now...

    My wildest guess is that probably you're using image lists that don't support alpha channel. One way would be to adjust your icons to 256-color scheme. (Your sample ico file has 8 icons in it: 4 with alpha channel and 4 without, so you may consider dropping the former ones.) You may also want to look at this sample on how to customize an image list for the alpha channel.

  13. #13
    Join Date
    Mar 2002
    Location
    Chicago, IL
    Posts
    255

    Re: Applying menu item images

    It actually does compile, but thanks anyway for help. I'll take a look at that link.

  14. #14
    Join Date
    Jul 2012
    Posts
    6

    Re: Applying menu item images

    Did you resolve this problem?

  15. #15
    Join Date
    Jul 2012
    Posts
    6

    Re: Applying menu item images

    at last, did you resolve this problem.And I met the same with you. I need your help.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)