ChrisR has asked for the wisdom of the Perl Monks concerning the following question:

I'm using Win32::GUI and the LostFocus event. When the LostFocus event fires, I would like to know which object will get the focus next. I have searched, and searched and couldn't find anything definitive. The closest guess I had was Win32::GUI->GetMessage() but I'm not sure I understand how to use it. The docs say:
GetMessage([MIN=0, MAX=0]) Retrieves a message sent to the window, optionally considering only me +ssages identifiers in the range MIN..MAX. If a message is found, the function returns a 7 elements array contain +ing: - the result code of the message - the message identifier - the wParam argument - the lParam argument - the time when message occurred - the x coordinate at which message occurred - the y coordinate at which message occurred If the result code of the message was -1 the function returns undef. N +ote that this function should not be normally used unless you know ve +ry well what you're doing.
I tried the following only printing the first four elements since I wasn't really interested in the time or click coordinates:
my @message = Win32::GUI->GetMessage(); print "MESSAGE: " . join(",",@message[0..3]) . "\n\n";
Which returned something like this:
MESSAGE: 1,49315,17,526238
So I get the result code which is always 1.
And the message identifier which is always 49315. I suppose this means LostFocus since that is the event that is being triggered.
Also the wParam is always 17. I thought this would be the handle of the window that lost focus but I'm obiviously mistaken and I have no idea what this means.
And the lParam which seems to correspond to the window that will get the focus. My main problem here is that I always thought you got the window handle from $object->{-handle} but that does not correspond to the value returned as lParam from Win32::GUI->GetMessage(). If I use Win32::GUI->GetFocus(), I get the same value returned as lParam. How do I get the handle of a window in a manner that will match the value returned by Win32::GUI->GetFocus() so that I can match it it up during the LostFocus event?

I may be, and probably am, totaly off track on this so I am very open to suggestions of a completely different way to handle this.

Thanks,
Chris

Replies are listed 'Best First'.
Re: Win32 - Where will the focus go?
by Util (Priest) on Sep 23, 2005 at 19:13 UTC

    Even though the LostFocus event handler is called before the GotFocus event handler, the value returned by GetFocus() actually changes just before the LostFocus event. Therefore, your solution should be as simple as calling $your_main_window->GetFocus() inside your LostFocus event handler; it should tell you who is getting the new focus.

    I may be wrong about this, but the example code below bears the thought out.
    Working, tested code:

    use strict; use warnings; use Win32::GUI; $| = 1; # Important! - Turn off buffering my $W1 = Win32::GUI::Window->new( -name => 'W1', -title => 'PerlMonks_494615', -pos => [ 100, 100 ], -size => [ 300, 200 ], ); my $T1 = $W1->AddTextfield( -name => 'T1', -text => '', -left => 10, -top => 10, -width => 200, -height => 25, -prompt => ['T1:', 80], ); my $T2 = $W1->AddTextfield( -name => 'T2', -text => '', -left => 10, -top => 35, -width => 200, -height => 25, -prompt => ['T2:', 80], ); $W1->Show(); print "$_->{-name}\t$_->{-handle}\n" foreach $W1, $T1, $T2; Win32::GUI::Dialog(); sub T1_GotFocus { print "\nT1_GotFocus - ",$W1->GetFocus(), "\n"; } sub T2_GotFocus { print "\nT2_GotFocus - ",$W1->GetFocus(), "\n"; } sub T1_LostFocus { print "\nT1_LostFocus - ",$W1->GetFocus(); } sub T2_LostFocus { print "\nT2_LostFocus - ",$W1->GetFocus(); }

      You're right. I should just forget about the Win32::GUI->GetMessage().

      I took another look at the problem after reading your post. The main difference is that if the focus is going to a combobox by the user pressing the TAB key or clicking in the textbox portion of the combobox the the handle is that of the textbox portion where GotFocus() returns the handle of the combobox. If the user clicks the arrow to dropdown the combobox list, the GotFocus idea works flawlessly.

      So how do I get the handles of both the textbox and the dropdown portions of a combobox?

        1. The simple solution. Each ComboBox can be configured as either
          • -dropdown, which allow edits, or
          • -dropdownlist, which does not allow edits.
          Of the two, only -dropdown has the split focus issue. So, if you can just use -dropdownlist, then your problem is solved.
        2. The less-simple solution. You can use Win32::API to call GetComboBoxInfo, which will give you the handles to the component controls. You can do this with straight-forward procedural code, but I chose to create a sub-class that provides the new methods GetEditControl and GetDropDownControl.

        Working, tested code:

        package Win32::GUI::Combobox_improved; use strict; use warnings; use Win32::GUI; use Win32::API; our @ISA = qw( Win32::GUI::Combobox ); # API GetComboBoxInfo: # http://msdn.microsoft.com/library/en-us/shellcc/platform/commctls/ +comboboxes/comboboxreference/comboboxfunctions/getcomboboxinfo.asp # Struct COMBOINFO: # http://msdn.microsoft.com/library/en-us/shellcc/platform/commctls/ +comboboxes/comboboxreference/comboboxstructures/comboboxinfo.asp # Struct RECT: # http://msdn.microsoft.com/library/en-us/gdi/rectangl_6cqa.asp # Note: I have flattened the rcItem and rcButton RECT structs, # because of bugs in Win32::API and Win32::API::Struct's # handling of nested structs, or in my own understanding of it. Win32::API::Struct->typedef( 'COMBOBOXINFO', qw( DWORD cbSize; LONG rcItem_left; LONG rcItem_top; LONG rcItem_right; LONG rcItem_bottom; LONG rcButton_left; LONG rcButton_top; LONG rcButton_right; LONG rcButton_bottom; DWORD stateButton; HWND hwndCombo; HWND hwndItem; HWND hwndList; )); Win32::API->Import("user32", <<'END_API') or die; BOOL GetComboBoxInfo( HWND hwndCombo, COMBOBOXINFO * pcbi ); END_API sub _GetComboBoxInfo { my ($self) = @_; my $hwndCombo = $self->{-handle}; my $pcbi = Win32::API::Struct->new('COMBOBOXINFO'); $pcbi->{cbSize} = $pcbi->sizeof(); my $rc = GetComboBoxInfo( $hwndCombo, $pcbi, ); return unless $rc; warn unless $hwndCombo == $pcbi->{hwndCombo}; return $pcbi; } # Retrieves the handle to the child edit control # portion of a ComboBox control. sub GetEditControl { my ($self) = @_; my $combo_box_info = $self->_GetComboBoxInfo() or return; return $combo_box_info->{hwndItem}; } # Retrieves the handle to the child drop-down control # portion of a ComboBox control. sub GetDropDownControl { my ($self) = @_; my $combo_box_info = $self->_GetComboBoxInfo() or return; return $combo_box_info->{hwndList}; } package main; use strict; use warnings; use Win32::GUI; $| = 1; # Important! - Turn off buffering my $W1 = Win32::GUI::Window->new( -name => 'W1', -title => 'PerlMonks_494615', -pos => [ 100, 100 ], -size => [ 300, 200 ], ); my $combo_style = '-dropdown'; # Allows edits #my $combo_style = '-dropdownlist'; # Does not allow edits my $cb1 = Win32::GUI::Combobox_improved->new( $W1, # Parent -name => 'CB1', -left => 10, -top => 10, -width => 125, -height => 100, -tabstop => 1, $combo_style => 1, ); my $cb2 = Win32::GUI::Combobox_improved->new( $W1, # Parent -name => 'CB2', -left => 140, -top => 10, -width => 125, -height => 100, -tabstop => 1, $combo_style => 1, ); { my %handle_to_parent; foreach my $cb ( $cb1, $cb2 ) { my $handle_cb = $cb->{-handle}; my $handle_edit = $cb->GetEditControl(); my $handle_dd = $cb->GetDropDownControl(); $handle_to_parent{ $handle_cb } = $handle_cb; $handle_to_parent{ $handle_edit } = $handle_cb; $handle_to_parent{ $handle_dd } = $handle_cb; } my %handle_to_name = ( $cb1->{-handle} => 'CB1', $cb2->{-handle} => 'CB2', ); sub dump_it { my $event = (caller(1))[3]; my $focus = $W1->GetFocus(); my $true_focus = $handle_to_parent{$focus} || $focus; my $name = $handle_to_name{$true_focus}; print "$event: focus going to $name\n"; } } $cb1->InsertItem($_) foreach qw(Able Baker Charlie); $cb2->InsertItem($_) foreach qw(Roger Fox Dog); $cb1->Select(0); $cb2->Select(0); $W1->Show(); Win32::GUI::Dialog(); sub CB1_GotFocus { dump_it() } sub CB2_GotFocus { dump_it() } sub CB1_LostFocus { dump_it() } sub CB2_LostFocus { dump_it() }

Re: Win32 - Where will the focus go?
by ariel2 (Beadle) on Sep 23, 2005 at 18:43 UTC
    I use Win32::GUI a lot, but I also don't know that much about the internals. I would suggest checking out this list. The search feature on sourceforge is awful but there's a lot of info there and the list members are very helpful.

    -ariel

      Thanks. I did check that list but couldn't find anything definitive there or on google which is usually my first stop. After extensive searching, I usually ask here first just because the answers are quite often better, the format is nicer, and the atmosphere is generally friendly. I will post the question there if nothing turns up here but I hate to double post.
Re: Win32 - Where will the focus go?
by traveler (Parson) on Sep 23, 2005 at 18:43 UTC
    There are two ways to interpret your question: 1) who will get the focus if I get the LostFocus, and 2) who now has focus now that LostFocus has fired. In the latter case GotFocus will fire for the object with the focus. I am not sure if the former is reasonable as there is no way to predict how focus would be lost (leaving the left or right of an object could cause different objects to get the focus).

    HTH, --traveler

      I'll try to more/less specific for clarification.

      Inside the sub for a _LostFocus event, I'd like to find out which object will have the focus next before the _LostFocus event returns.

      As I understand it, the _LostFocus event is fired when the current object looses the focus and before the next object gets the focus.

      Update: As pointed out below, I was mistaken about the order of events.