in reply to Win32::GUI::Menu icon problem - I need help !

Win32::GUI doesn't actually allow you to change the icons of menu items directly. Instead you will need to use some Win32 API functions. You can find more information about this method on the Win32::GUI mailing lists here. Unfortunately, this method only works up to Windows XP. For later versions, one method that you could use is owner-drawn menu items. Here is an example:

#!perl use strict; use warnings; use PeekPoke qw(peek poke); use Win32::API; use Win32::GUI qw(); use Win32::GUI::Constants qw( CW_USEDEFAULT WM_MEASUREITEM WM_DRAWITEM ODA_DRAWENTIRE SRCCOPY ); use constant { MENU_ITEMS => 6, # These are needed for creating menu icons MIIM_BITMAP => 0x00000080, MIM_STYLE => 0x00000010, MNS_CHECKORBMP => 0x04000000, MNS_NOCHECK => 0x80000000, HBMMENU_CALLBACK => 0xFFFFFFFF, HBMMENU_SYSTEM => 1, HBMMENU_MBAR_RESTORE => 2, HBMMENU_MBAR_MINIMIZE => 3, HBMMENU_MBAR_CLOSE => 5, HBMMENU_MBAR_CLOSE_D => 6, HBMMENU_MBAR_MINIMIZE_D => 7, HBMMENU_POPUP_CLOSE => 8, HBMMENU_POPUP_RESTORE => 9, HBMMENU_POPUP_MAXIMIZE => 10, HBMMENU_POPUP_MINIMIZE => 11, }; # Import the Win32 API functions we need Win32::API->Import( 'user32.dll', 'SetMenuItemInfo', 'LILP', 'L' ); Win32::API->Import( 'user32.dll', 'SetMenuInfo', 'LP', 'L' ); # Create a simple menu # We specify our own menu item id since we need to check the id of the + item # that needs to be drawn in the WM_DRAWITEM hook below. my $mnuMain = Win32::GUI::Menu->new( 'Menu' => 'mnuMenu', map { ( "> Item $_" => { -name => "mnuMenuItem$_", -id => $_ } ) +} 1 .. MENU_ITEMS, ); # Remove check mark space my $menuinfo = pack 'LLLILLL', 28, # Size MIM_STYLE, # Mask MNS_NOCHECK, # Style 0, # Max height of menu 0, # Background brush 0, # Context help identifier 0; # Application defined value SetMenuInfo( $mnuMain->{mnuMenu}->{-handle}, $menuinfo ); # Create some simple bitmaps my @bitmaps; foreach( 1 .. MENU_ITEMS ){ my $r = int rand 256; my $g = int rand 256; my $b = int rand 256; my $data = pack 'C*', map { $r, $g, $b, 0 } 0 .. ( ( 16 ** 2 ) - 1 + ); push @bitmaps, Win32::GUI::Bitmap::Create( 16, 16, 1, 32, $data ); } # Specify that bitmap for each menu item will be owner drawn my $menuiteminfo = pack 'IIIIILLLLLIL', 48, # Size MIIM_BITMAP, # Mask 0, # Type 0, # State 0, # ID 0, # SubMenu 0, # Checked bitmap 0, # Unchecked bitmap 0, # Item Data 0, # Type Data 0, # Length of menu item text HBMMENU_CALLBACK; # Bitmap will be owner drawn SetMenuItemInfo( $mnuMain->{mnuMenu}->{-handle}, $_, 0, $menuiteminfo +) foreach 1 .. MENU_ITEMS; # Create a window my $winMain = Win32::GUI::Window->new( -name => 'winMain', -text => 'Win32::GUI Menu Icons', -pos => [ CW_USEDEFAULT, CW_USEDEFAULT ], -size => [ 320, 240 ], -menu => $mnuMain, ); # Create a hook for the WM_MEASUREITEM message that specifies the size + of the icon $winMain->Hook( WM_MEASUREITEM, sub { # dump \@_; my( $self, $wParam, $lParam, $type, $msgcode ) = @_; return 1 unless $type == 0; return 1 unless $msgcode == WM_MEASUREITEM; if( $wParam == 0 ){ # Process if message was sent by a menu poke( $lParam + 12, 16 ); # 12 is the offset of the item +Width member poke( $lParam + 16, 16 ); # 16 is the offset of the item +Height member } return 1; }, ); # Create a hook for the WM_DRAWITEM message to draw the bitmap for eac +h menu item $winMain->Hook( WM_DRAWITEM, sub { my( $self, $wParam, $lParam, $type, $msgcode ) = @_; if( $wParam == 0 ){ # Process if message is sent by a menu # Unpack data from the structure my %drawitem; @drawitem{qw(CtlType CtlID itemID itemAction itemState hwn +dItem hDC left top right bottom itemData)} = unpack 'IIIIILLllllL', u +npack 'P48', pack 'L', $lParam; # Draw the bitmap if( $drawitem{'itemAction'} == ODA_DRAWENTIRE ){ my $hDC = $drawitem{'hDC'}; my $memdc = Win32::GUI::DC::CreateCompatibleDC($hDC +); my $oldimage = $memdc->SelectObject( $bitmaps[ $drawit +em{'itemID'} - 1 ] ); Win32::GUI::DC::BitBlt( $hDC, $drawitem{'left'}, $drawitem{'top'}, $drawitem{'right'} - $drawitem{'left'}, $drawitem{'bottom'} - $drawitem{'top'}, $memdc, 0, 0, SRCCOPY ); } return 1; } }, ); $winMain->Show(); Win32::GUI::Dialog(); __END__

Update: Link fixed.

Replies are listed 'Best First'.
Re^2: Win32::GUI::Menu icon problem - I need help !
by Ahmet (Novice) on Dec 14, 2010 at 06:02 UTC

    Excellent jop. kejohm Thank you very much :)

    I managed to... These are my codes

    use strict; use warnings; use Win32::API(); Win32::API->Import('user32', 'SetMenuItemInfo', 'LILP', 'L') or die; use Win32::GUI (); use Win32::GUI::DIBitmap(); sub MIIM_BITMAP() {0x00000080} my $menu = Win32::GUI::MakeMenu( 'Popup' => 'Popup', '>Item &1' => { -name => 'Item1', -onClick => sub { print "Item1\n +"; 0; }, }, '>-' => 'Seperator', '>Item &4' => { -name => 'Item4', -onClick => sub { print"Item4\n" +; 0; }, }, ); my $mw = Win32::GUI::Window->new( -size => [400,300], -menu => $menu, -name => "test", ); my $hbap = new Win32::GUI::Bitmap ('aon2.bmp'); my $hbmp = $hbap->{-handle}; my $hmenu = $menu->{Popup}->{-handle}; my $mii = pack( 'IIIIILLLLLIL', 12 * 4, # cbsize = sizeof(MENUITEMINFO) MIIM_BITMAP, # fMask = MIIM_BITMAP 0, # fType - unused 0, # fState - unused 0, # wID - unused 0, # hSubMenu - unused 0, # hbmpChecked - unused 0, # hbmpUnchecked - unused 0, # dwItemData - unused 0, # dwTypeData - unused 0, # cch - unused $hbmp, # hbmpItem ); SetMenuItemInfo($hmenu, 2, 1, $mii); $mw->Center(); $mw->Show(); Win32::GUI::Dialog();

    use Win32::API(); Win32::API->Import('user32', 'SetMenuItemInfo', 'LILP', 'L') or die; Win32::API->Import('user32', 'SetMenuInfo', 'LP', 'L') or die; use Win32::GUI qw(CW_USEDEFAULT SM_CXMENUCHECK SM_CYMENUCHECK TRANSPAR +ENT); use Win32::GUI::DIBitmap(); sub MIIM_BITMAP() {0x00000080} sub MIM_STYLE() {0x00000010} sub MIM_BACKGROUND() {0x00000002} my $menu = Win32::GUI::MakeMenu( 'Popup' => 'Popup', '>Item &1' => { -name => 'Item1', -onClick => sub { print "Item1\n +"; 0; }, }, '>-' => 'Seperator', '>Item &4' => { -name => 'Item4', -onClick => sub { print"Item4\n" +; 0; }, }, ); $po = new Win32::GUI::Brush( -color => 000); my $mw = Win32::GUI::Window->new( -left => CW_USEDEFAULT, -size => [400,300], -menu => $menu, -name => "test", ); $hbap = new Win32::GUI::Bitmap ('aon2.bmp'); $hbmp = $hbap->{-handle}; $hmenu = $menu->{Popup}->{-handle}; my $mi = pack( 'LLLILLL', 12 * 4, # cbsize = sizeof(MENUITEMINFO) MIM_BACKGROUND, # fMask = MIM_STYLE 0, 0, # cyMax - unused $po, # hbrBack - unused 0, # dwContextHelpID - unused 0, # dwMenuData - unused ); SetMenuInfo($hmenu, $mi); my $mii = pack( 'IIIIILLLLLIL', 12 * 4, # cbsize = sizeof(MENUITEMINFO) MIIM_BITMAP, # fMask = MIIM_BITMAP 0, # fType - unused 0, # fState - unused 0, # wID - unused 0, # hSubMenu - unused 0, # hbmpChecked - unused 0, # hbmpUnchecked - unused 0, # dwItemData - unused 0, # dwTypeData - unused 0, # cch - unused $hbmp, # hbmpItem ); SetMenuItemInfo($hmenu, 2, 1, $mii); $mw->Center(); $mw->Show(); Win32::GUI::Dialog();

    But now, not show the "Transparent" png images; i have looked transparent png images in a main window with "AddGraphic" and "AddLabel" modules !!... I changed my mind ! and write this code;
    use Win32::API(); Win32::API->Import('user32', 'SetMenuItemInfo', 'LILP', 'L') or die; Win32::API->Import('user32', 'SetMenuInfo', 'LP', 'L') or die; use Win32::GUI qw(CW_USEDEFAULT SM_CXMENUCHECK SM_CYMENUCHECK TRANSPAR +ENT); use Win32::GUI::DIBitmap(); sub MIIM_BITMAP() {0x00000080} sub MIM_STYLE() {0x00000010} sub MIM_BACKGROUND() {0x00000002} my $menu = Win32::GUI::MakeMenu( 'Popup' => 'Popup', '>Item &1' => { -name => 'Item1', -onClick => sub { print "Item1\n +"; 0; }, }, '>-' => 'Seperator', '>Item &4' => { -name => 'Item4', -onClick => sub { print"Item4\n" +; 0; }, }, ); $po = new Win32::GUI::Brush( -color => 000); my $mw = Win32::GUI::Window->new( -left => CW_USEDEFAULT, -size => [400,300], -menu => $menu, -name => "test", ); $hbap = new Win32::GUI::Bitmap ('aon2.bmp'); $hbmp = $hbap->{-handle}; $hmenu = $menu->{Popup}->{-handle}; my $mi = pack( 'LLLILLL', 12 * 4, # cbsize = sizeof(MENUITEMINFO) MIM_BACKGROUND, # fMask = MIM_STYLE 0, 0, # cyMax - unused $po, # hbrBack - unused 0, # dwContextHelpID - unused 0, # dwMenuData - unused ); SetMenuInfo($hmenu, $mi); my $mii = pack( 'IIIIILLLLLIL', 12 * 4, # cbsize = sizeof(MENUITEMINFO) MIIM_BITMAP, # fMask = MIIM_BITMAP 0, # fType - unused 0, # fState - unused 0, # wID - unused 0, # hSubMenu - unused 0, # hbmpChecked - unused 0, # hbmpUnchecked - unused 0, # dwItemData - unused 0, # dwTypeData - unused 0, # cch - unused $hbmp, # hbmpItem ); SetMenuItemInfo($hmenu, 2, 1, $mii); $mw->Center(); $mw->Show(); Win32::GUI::Dialog();
    Basically i change the popup menu "Color" and "Transparent" problem will be solved... This my idea but not change the popup menu color !!!

      The problem might where you are setting the background brush for the menu. You need to pass the handle of the brush, rather than the brush itself. So instead of this:

      my $mi = pack( 'LLLILLL', 12 * 4, MIM_BACKGROUND, 0, 0, $po, # <=== problem might be here 0, 0, );

      you need to do this:

      my $mi = pack( 'LLLILLL', 12 * 4, MIM_BACKGROUND, 0, 0, $po->{-handle}, # <=== change to this 0, 0, );

        Thank you very much for posts, kejohm.

        I'm working on a program for 1 month, So tired !,

        I forget the codes :)

        Thanks kejohm...

        Thanks Perlmonks...

        Regars...