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/

Reply via email to