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
> [email protected]
> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users
http://perl-win32-gui.sourceforge.net/