When I first looked at Win32::GUI for the first time many many years
ago (4? ok, not so many) I found it kind of confusing how the objects
and events worked.
Coming from an OO background and with experience from a few other
window toolkits (VB and Borland TurboVision among others) I would have
expected to subclass the Window class, create an object, add controls
to the object, and then I would defined methods in my subclass to be
called when events fired. Kind of like this:
package DemoWindow;
#My DemoWindow is-a Window...
use base qw(Win32::GUI::Window);
#...but with event handlers for events that may fire
sub btnOk_Click { my $self = shift; #the Window object
#Change text of the clicked button
$self->btnOk->Text( "Ok - " . int(rand(100)) );
return(1);
}
But that's not how it works. Instead, event handlers based on the
-name of the windows and controls created. They are sub routines
called in a procedural fashion which requires me as an application
programmer to keep track of which window the event belongs to. This is
not very convenient.
I have not yet seen any "best practice" emerge for dealing with this.
Either the window variable needs to be a global or a singleton (which
in this case is the same thing, but without the stigma of globals, and
people don't argue back when you bring up the havey artillery of
design patterns), or it has to be connected to a global or singleton
which is your "application" object or whaterver. It's nothing that
can't be solved, but it's either inconvenient or not very maintainable.
One other drawback with the event-handler-as-procedure approach is
that there can only be one instance of the window, because if you
create a new window with the exact same names the event handler sub
has no way to determine which window fired the event. This can be
coded around at great inconvenience (with Perl, few things are
impossible).
My point is: If only the Window object (or the window object of the
control) firing off the event was passed as the first parameter to the
event handler everything would be so much easier to live with. Finding
the event handler sub in the correct package (OO style) would be a boon.
Actually, the result of my holiday hacking today is a module that
pretty much does this. Win32::GUI::Window::Object
http://www.bahnhof.se/~johanl/perl/Win32GUI/Window/
The synopsis script (below) creates three distinct windows of the same
class DemoWindow. The event handlers are methods on a subclass of
Win32::GUI::Window, so the context ($self) for all events is the
current Window::GUI::Window object.
Consider this a proof-of-concept. A test of whether it could be done
or not. I've had the idea for a long time, but never had the free time
and motivation to actually do it. I have obviously not done anything
real with this yet :)
- Is this something that seems useful to proceed with? At least the
concepts, if not the code?
- Is this something that can easily be solved from within Win32::GUI
XS code, passing the window object as the first variable ot the event
handlers? Perhaps using Perl's OO mechanism so that the correct
package is used? Doing it the real way is definitely more stable than
my hack.
- The subclassing isn't necessary, but could be useful. At the moment,
with the objects as hash keys in the object, there is a high risk of
clobbering them unintentionally, should people start subclassing
Win32::GUI::Window en masse. Perhaps they could be moved to a
"_controls" hash ref property of the window or something? Would that
be difficult to use from XS code?
So finally, an example program using Yet Another Event Model:
http://www.bahnhof.se/~johanl/perl/Win32GUI/Window/synopsis.pl.txt
#!/usr/local/bin/perl -w
use strict;
use Data::Dumper;
use Win32::GUI;
use lib ("../lib");
use Win32::GUI::Window::Object;
for (1..3) {
my $id = int(rand(100));
my $win = DemoWindow->winCreate($id);
$win->Show();
}
Win32::GUI::Dialog();
package DemoWindow;
#Inherit from the new Window-as-object class
use base qw(Win32::GUI::Window::Object);
#A demo property to give it some identity
use Class::MethodMaker get_set => [ "no" ];
#Class method to create/build a window of this class. It
#could eventually be a window built by TGL.
#
#This could be in the new() method as well, calling the
#SUPER::new() to create the object, then setting the no()
#property.
#
sub winCreate { my $pkg = shift;
my ($no) = @_;
my $self = $pkg->new(
-left => 100 + int(rand(400)),
-top => 50 + int(rand(200)),
-width => 300,
-height => 100,
-name => "winMain",
-text => "Window $no",
);
$self->no($no); #Set the demo property
my $btnHelloWorld = $self->AddButton(
-name => "btnHelloWorld",
-text => "Hello world!",
-left => 10,
-top => 10,
-height => 20,
-width => 100,
);
return($self);
}
#Event handlers are ordinary methods, with $self as
#the first parameter as usual. This gives context to the
#event, making it possible to have many instances of the
#same window class.
sub winMain_Terminate { my $self = shift;
print "winMain_Terminate from DemoWindow with no (" . $self->no .
")\n";
return(-1);
}
sub btnHelloWorld_Click { my $self = shift;
my $no = $self->no();
print "btnHelloWorld_Click in DemoWindow no == $no\n";
$self->Text("Window $no - " . int(rand(100)) );
return(1);
}
__END__
/J
-------- ------ ---- --- -- -- -- - - - - -
Johan Lindström Sourcerer @ Boss Casinos [EMAIL PROTECTED]
Latest bookmark: "ACM Queue - Code Spelunking Exploring Cavernous..."
<http://www.acmqueue.com/modules.php?name=Content&pa=showpage&pid=67&page=7>
dmoz (1 of 4): /Arts/Music/Bands_and_Artists/T/ 20
-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills. Sign up for IBM's
Free Linux Tutorials. Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id78&alloc_id371&op=click
_______________________________________________
Perl-Win32-GUI-Users mailing list
Perl-Win32-GUI-Users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users