Thank you Kevin for the rich example, here is a picture of what i got: http://img130.imageshack.us/img130/1870/customlistbox.png the two codes are inspiring and very usefull. thanks peter
Kevin Marshall-4 wrote: > > Hi everyone, > > After much experimentation, I have finally succeeded in creating an > owner-drawn control in Win32::GUI. I decided to create this post > detailing how to create an owner-drawn control in case someone else has > the need to use one. > > For those of you who don't know, an owner-drawn control allows the user > more control over the appearance of the control. This usually involves > responding to messages sent whenever the control needs to be drawn and > drawing the control in anyway that you wish. > > In order to get my sample to work you will need to install the PeekPoke > module from CPAN. This module allows reading and writing of data to and > from arbitrary memory locations. This is needed to set the height of the > items of the listbox. More on this below. > > This example was created using ActiveState Perl v5.12.0 running on > Windows XP. > > For this example, I will demonstrate how to create an owner-drawn > listbox. The listbox will have items with a larger height, will display > two lines of text with different formats, and an image. > > All of the files related to this example at the bottom of this post. > > Anyway, on with the example. > > I decided to store the information about each listbox item in an > external XML file and use XML::Simple to parse it. This makes it rather > simple to change the information for the listbox items. > > I also created 8 simple 40x40 bitmaps that will be displayed in each > listbox item. > > Now for a description of the code. > > The first step is to create a window for our listbox and load our XML > data from the file using XML::Simple::XMLin(). This is all fairly > simple, so I won't bother explaining. > > Next step is to create a hook for the WM_MEASUREITEM message. This > message is sent when the listbox is created so the user can specify the > width and height of the listbox items. The $lParam variable contains the > address of the structure that is passed to the message, which needs to > be filled out. Here we use the poke() function to write the desired > height into the structure, which in our case is 50. 16 is the offset of > the itemHeight member of the structure which needs to contain the height > that we want when the message returns. > > Next a hook is created for the WM_DRAWITEM message. This message is sent > whenever an item in the listbox requires drawing. First step is to > unpack the structure that is passed to the message. If the itemID > contains -1, then the listbox is empty, so we simply return from the sub > if this occurs. Otherwise, it contains the zero-based index of the item > being drawn. The itemAction member contains the action required for the > drawing. Here we respond if the entire item needs drawing. To begin with > we draw the bitmap for the item. First we create a compatible DC from > the DC that is passed to the message, then select the bitmap for the > current item into it. Then we BitBlt() the contents of the compatible DC > into the item DC. Next we need to draw the text that will be displayed > in the item. We create a large font that will be used for the item's > heading, and select the font into the item DC, remembering the old font. > Then we draw the text into the item DC using DrawText(). Next we select > the old font, and draw the other text that will be displayed in the > item. That completes the drawing for the item, so we return from our sub. > > Next step is to create our listbox. The only difference here from > creating an ordinary listbox is to specify the LBS_OWNERDRAWFIXED style. > This specifies that the listbox will be owner-drawn, and all the items > have the same height. An alternative would be to use the > LBS_OWNERDRAWVARIABLE style instead, which specifies that each item will > have a different height. In this case, the WM_MEASUREITEM would be sent > for each item when the control is created, not just once like our case. > > Next we loop through each item returned from the XML file, create a > Win32::GUI::Bitmap from the file name specified in the file, and add the > relevant data to an array which will be used when drawing the listbox > items. We also add an item to the listbox using the text as a place > holder, although it won't get drawn, so it doesn't matter what is > inserted here. Then we simply show the window and enter the dialog phase. > > The listbox acts like any other listbox, it just has larger items and > different content. This is demonstrated here when an item is selected: > the heading and text of the selected item are printed. > > That's it for creating an owner-drawn listbox. > > Various other controls can also be owner-draw, such as buttons, labels, > and combo boxes. I have yet to try it with other controls, but it > shouldn't be much different from a listbox. > > More information about owner-draw controls can be found in the Windows > SDK Documentation. > > I hope that someone finds this example useful. If you come up with > something interesting, I wouldn't mind a reply post detailing what you > have done. > > Kevin. > > Here are the files: > > This is the main code: > > #!perl > ################################################################################ > # > # customlistbox.pl > # > # Win32::GUI Owner-drawn Controls > # > # This script demonstrates the creation and use of an owner-drawn > listbox. > # > # Requirements: > # Win32::GUI > # PeekPoke > # XML::Simple > # > # This program was written using ActiveState Perl 5.12.0 Build 1200 > running on > # Windows XP and using Win32::GUI v1.06, PeekPoke v0.01, and > XML::Simple v2.18 > # > ################################################################################ > use strict; > use warnings; > > use PeekPoke qw(poke); > use Win32::GUI qw(); > use Win32::GUI::Constants qw(CW_USEDEFAULT WM_MEASUREITEM WM_DRAWITEM > ODA_DRAWENTIRE SRCCOPY DT_LEFT DT_TOP DT_WORDBREAK > LBS_OWNERDRAWFIXED); > use XML::Simple; > > # Create our main window > my $winMain = Win32::GUI::Window->new( > -name => 'winMain', > -text => 'Owner-Drawn Listbox', > -size => [ 320, 240 ], > -minwidth => 320, > -minheight => 240, > ); > > # Load XML data > my $ListBoxItems = XMLin('customlistbox.xml'); > my @Items; > > # Create a hook to handle WM_MEASUREITEM message. This message is used > to set the > # height of the listbox items. > $winMain->Hook( > WM_MEASUREITEM, > sub { > my( $self, $wParam, $lParam, $type, $msgcode ) = @_; > return 1 unless $type == 0; > return 1 unless $msgcode == WM_MEASUREITEM; > # Write desired height of items to structure. 16 is the offset > of the > # itemHeight member of the MEASUREITEMSTRUCT structure > poke( $lParam + 16, 50 ); > return 1; > }, > ); > > # Create a hook to handle the WM_DRAWITEM message. This message is sent > whenever > # a listbox item needs drawing > $winMain->Hook( > WM_DRAWITEM, > sub { > my( $self, $wParam, $lParam, $type, $msgcode ) = @_; > my %drawitem; > # Unpack data from the structure > @drawitem{qw(CtlType CtlID itemID itemAction itemState hwndItem > hDC left > top right bottom itemData)} = unpack 'IIIIILLllllL', unpack > 'P48', > pack 'L', $lParam; > # itemID will contain -1 if there are no items, so we just return > return 1 if $drawitem{'itemID'} == -1; > > # Draw the bitmap and text for the list box item. > if( $drawitem{'itemAction'} == ODA_DRAWENTIRE ){ > my $hDC = $drawitem{'hDC'}; > > # Display the bitmap associated with the item. > my $image = $Items[ $drawitem{'itemID'} ]{'image'}; > my $memdc = Win32::GUI::DC::CreateCompatibleDC($hDC); > my $oldimage = $memdc->SelectObject($image); > Win32::GUI::DC::BitBlt( > $hDC, $drawitem{'right'} - 45, $drawitem{'top'} + 5, > 40, 40, $memdc, 0, 0, SRCCOPY > ); > > # Display the text associated with the item. > my $titlefont = Win32::GUI::Font->new( > -height => 12, > -weight => 700, > ); > my $oldfont = Win32::GUI::DC::SelectObject( $hDC, $titlefont > ); > Win32::GUI::DC::DrawText( > $hDC, > $Items[ $drawitem{'itemID'} ]{'heading'}, > $drawitem{'left'} + 5, $drawitem{'top'} + 5, > $drawitem{'right'} - 50, $drawitem{'bottom'} - 5, > ); > Win32::GUI::DC::SelectObject($drawitem{'hDC'}, $oldfont); > Win32::GUI::DC::DrawText( > $hDC, > $Items[ $drawitem{'itemID'} ]{'text'}, > $drawitem{'left'} + 5, $drawitem{'top'} + 30, > $drawitem{'right'} - 50, $drawitem{'bottom'} - 5, > DT_LEFT | DT_TOP | DT_WORDBREAK > ); > } > return 1; > } > ); > > # Create our listbox control > my $lsbCustom = $winMain->AddListbox( > -name => 'lsbCustom', > -pos => [ 10, 10 ], > -size => [ $winMain->ScaleWidth() - 20, > $winMain->ScaleHeight() - 20 ], > -nointegralheight => 1, > -vscroll => 1, > -pushstyle => LBS_OWNERDRAWFIXED, > ); > # Add items to listbox > foreach my $item ( @{ $ListBoxItems->{'item'} } ){ > my $bmp = Win32::GUI::Bitmap->new( $item->{'image'} ); > push @Items, { > heading => $item->{'heading'}, > text => $item->{'text'}, > image => $bmp, > }; > $lsbCustom->InsertString( $item->{text} ); > } > > $winMain->Show(); > > Win32::GUI::Dialog(); > > sub winMain_Terminate { > return -1; > } > > sub winMain_Resize { > my $width = $winMain->ScaleWidth(); > my $height = $winMain->ScaleHeight(); > $lsbCustom->Resize( $width - 20, $height - 20 ); > return 1; > } > > sub lsbCustom_SelChange { > my $index = $lsbCustom->GetCurSel(); > print <<EOT; > $Items[$index]{heading} > $Items[$index]{text} > EOT > return 1; > } > > __END__ # of customlistbox.pl > > > > This is the XML file that stores the data for each item in the listbox: > > <!-- customlistbox.xml --> > <listboxitems> > <item> > <heading>Item 1</heading> > <image>item1.bmp</image> > <text>This is some text for item 1</text> > </item> > <item> > <heading>Item 2</heading> > <image>item2.bmp</image> > <text>This is some text for item 2</text> > </item> > <item> > <heading>Item 3</heading> > <image>item3.bmp</image> > <text>This is some text for item 3</text> > </item> > <item> > <heading>Item 4</heading> > <image>item4.bmp</image> > <text>This is some text for item 4</text> > </item> > <item> > <heading>Item 5</heading> > <image>item5.bmp</image> > <text>This is some text for item 5</text> > </item> > <item> > <heading>Item 6</heading> > <image>item6.bmp</image> > <text>This is some text for item 6</text> > </item> > <item> > <heading>Item 7</heading> > <image>item7.bmp</image> > <text>This is some text for item 7</text> > </item> > <item> > <heading>Item 8</heading> > <image>item8.bmp</image> > <text>This is some text for item 8</text> > </item> > </listboxitems> > <!-- end of customlistbox.xml --> > > If you execute this script, it will create a file called pics.7z file, > which will contain the 8 bitmaps needed for this sample: > > #!perl > use strict; > use warnings; > > use MIME::Base64; > > open my $fh, '>', 'pics.7z' or die $!; > binmode $fh; > print {$fh} MIME::Base64::decode( > 'N3q8ryccAANPwVVtOwEAAAAAAAAjAAAAAAAAAJASfkEAIRNayxcGoME2nyL7I4JzfZi4oHYg66A8 > nm6WsRvMHTne+oX2PHIJM7ayDfdnbZ0DmCN8Mf70re7XhMyBeX4+OafcrXhvLiG669M+EMuzgnG7 > JvuHqsUDJQokFWg0SzmcesrNrAHXMApzksKeghHSU1HMZ64/6cXUSTzQaCJdREH7ieEAAACBMweu > D9Uvw85WbCkfSCtBMmjGwE0B4XqeDwoyHBt1/T8r3bH8o1BWWPseZbEvATR9EeL4s4UpAsX59y9L > RF7bndv+H7Dz0pCHk43K2555nX5iAiwmibuV8uDOx83QgHHTqy9AORcPkqPfO6duMlkZ+UYo1t0/ > TapX+1Jl1LSaAcpSost05OeRFdSSTWGt3tvzEPzEG8sIrZ+vTlWBzDSQrvvsJkdLC0r63jRJhP2+ > sK6GAAAXBoCFAQmAtgAHCwEAASMDAQEFXQAQAAAMgWMKAVQcA6kAAA=='); > close $fh; > > __END__ > > > > > ------------------------------------------------------------------------------ > Sell apps to millions through the Intel(R) Atom(Tm) Developer Program > Be part of this innovative community and reach millions of netbook users > worldwide. Take advantage of special opportunities to increase revenue and > speed time-to-market. Join now, and jumpstart your future. > http://p.sf.net/sfu/intel-atom-d2d > _______________________________________________ > Perl-Win32-GUI-Users mailing list > Perl-Win32-GUI-Users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users > http://perl-win32-gui.sourceforge.net/ > > -- View this message in context: http://old.nabble.com/Win32%3A%3AGUI-Owner-Drawn-Controls-tp29558631p29560854.html Sent from the perl-win32-gui-users mailing list archive at Nabble.com. ------------------------------------------------------------------------------ Start uncovering the many advantages of virtual appliances and start using them to simplify application deployment and accelerate your shift to cloud computing. http://p.sf.net/sfu/novell-sfdev2dev _______________________________________________ Perl-Win32-GUI-Users mailing list Perl-Win32-GUI-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users http://perl-win32-gui.sourceforge.net/