|
From: Kevin M. <kej...@ho...> - 2010-08-29 13:07:59
|
Octavian,
According to the Windows docs, the common controls are automatically
accessible, which are what Win32::GUI uses, whereas custom controls
require additional setup.
Kevin.
> Hi Kevin,
>
> I was asking this because all the standard controls which can be created with Win32::GUI are accessible without doing anything special.
>
> Octavian
>
> ----- Original Message -----
> From: "Kevin Marshall"<kej...@ho...>
> To: "Octavian Rasnita"<ora...@gm...>
> Cc:<per...@li...>
> Sent: Saturday, August 28, 2010 1:56 PM
> Subject: Re: [perl-win32-gui-users] Win32::GUI Owner Drawn Controls
>
>
>
>> Hi Octavian,
>>
>> Thanks for your comments. It's good to know that you find it useful.
>>
>> I have been looking into Windows Accessibility to see how it works, and
>> it seems that under normal circumstances (i.e. creating GUIs using C++,
>> rather than Perl), the custom controls must provide an interface to the
>> Accessibility API, which accessibility programs can use to interact with
>> the control. Unfortunately, it looks like it is probably beyond the
>> scope of the Win32::GUI module.
>>
>> Perhaps it is something that could be looked into for a separate module.
>>
>> Other people may have thoughts on the topic.
>>
>> Thanks again,
>>
>> Kevin.
>>
>>
>>> Hi Kevin,
>>>
>>> Congratulations for the program!
>>>
>>> I have tested it with a screen reader and it works. I added the -dialogui => 1 option to the $winMain object to be able to use the keyboard for changing the focus.
>>>
>>> The only problem, which is an important one, is that if I arrow up or down in the list box, the screen reader announces just things like "item 1 of 8, item 2 of 8" and so on, without telling the label of the current item as it should.
>>>
>>> Do you (or somebody else) have any idea how to add accessibility features (MSAA) to this custom control in order to be as useful as a standard control?
>>>
>>> Basicly it should also report the labels of the list box items and not just print them.
>>>
>>> Thank you.
>>>
>>> Octavian
>>>
>>> ----- Original Message -----
>>> From: "Kevin Marshall"<kej...@ho...>
>>> To:<per...@li...>
>>> Sent: Saturday, August 28, 2010 8:07 AM
>>> Subject: [perl-win32-gui-users] Win32::GUI Owner Drawn Controls
>>>
>>>
>>>
>>>
>>>> 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
>>>> Per...@li...
>>>> https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users
>>>> http://perl-win32-gui.sourceforge.net/
>>>>
>>>>
>>>
>>>
>
>
|