Dear all, especially perl hackers, please excuse the long posting and the rather general questions, I hope that I haven't offended the group's charter - or anyone who doesn't like Perl. I have written a perl module that generates perl source code from a Glade UI definition file. Glade is of course the beautiful Gtk UI builder written by Damon Chaplin. I don't have much experience of object-oriented programming so I would appreciate any advice that people could give me about good practice in the world of object-oriented perl. I have tried to follow the examples in perltoot and I have 'read' perltootc but I am not sure how much I have _really_ understood about the OO apprach in general and OO perl in particular. The intention is to produce perl classes that construct a UI using Gtk and can be inherited and extended by the developer, for instance to provide signal handlers for the widgets in the UI. It is important that when the UI is changed and the UI construction classes are regenerated, the programmer should not need to change any of her own code in order to use the new UI classes (with dynamically AUTOLOADed signal handlers for any signal handlers that have not yet been written). The programmer might want to construct and show several copies of any of the UIs simultaneously. At the moment I generate a separate class for each toplevel window/dialog that has been defined and all the classes are perl packages in one single source file. If I haven't put you all off yet, do you think that I am doing this in a 'proper' and scalable OO way? I have real problems throwing off my modular habits so please tell me if I have failed to really grasp the OO nettle. I expect the programmer's signal handlers to be in a simple perl module and to be Export()ed so that they are visible at generation time. This is so that the UI can function during the generation run. This approach falls down if any of the signal handlers construct one of the toplevel windows/dialogs that are being generated of course. It does however allow a shorter development cycle and also dynamic construction of simple UIs from a string of XML containing a Glade UI definition. Perhaps it would be better just to expect the programmer to subclass the UI and provide the signal handlers in this new subclass and forget about trying to run the UI during the generation phase at all. If anyone is interested, a development version of the Glade-Perl source code generator is available from: http://freespace.virgin.net/dermot.musgrove/computers/perl/ Thanks in advance you for absolutely any advice that you can offer. The (snipped) top of one such generated class/package would be (in the file Generated/BusForm.pm) ---------------8<----------------------------- package BusFrame; require 5.000; use English; use strict 'vars', 'refs', 'subs'; BEGIN { # Run-time utilities and vars use Glade::PerlRun; # Existing signal handler modules use Existing::BusForm_mySUBS; use vars qw( @ISA $AUTOLOAD %fields %stubs); # Tell interpreter who we are inheriting from @ISA = qw( Glade::PerlRun ); } %fields = ( # These are the data fields that you can set/get using the dynamic # calls provided by AUTOLOAD (and their initial values). # eg $class->FORMS($new_value); sets the value of FORMS # $current_value = $class->FORMS; gets the current value of FORMS TOPLEVEL => undef, FORM => undef, PACKAGE => 'BusFrame', VERSION => '0.0.1', AUTHOR => 'Dermot Musgrove <dermot.musgrove\@virgin.net>', DATE => 'Mon Jul 26 18:38:55 BST 1999', ); %stubs = ( # These are signal handlers that will cause a message_box to be # displayed by AUTOLOAD if there is not already a sub of that name # in any module specified in 'use_modules'. 'about_Form' => undef, 'destroy_Form' => undef, 'on_quit1_activate' => undef, ); sub AUTOLOAD { my $self = shift; my $type = ref($self) or die "$self is not an object"; my $name = $AUTOLOAD; $name =~ s/.*://; # strip fully-qualified portion if (exists $self->{_permitted_fields}->{$name} ) { # This allows dynamic data methods - see %fields above # eg $class->UI('new_value'); # or $current_value = $class->UI; if (@_) { return $self->{$name} = shift; } else { return $self->{$name}; } } elsif (exists $stubs{$name} ) { # This shows dynamic signal handler message_box for %stubs above __PACKAGE__->show_skeleton_message( $AUTOLOAD."\n (AUTOLOADED by ".__PACKAGE__.")", [$self, @ARG], __PACKAGE__, 'pixmaps/Logo.xpm'); } else { die "Can't access method `$name' in class $type"; } } sub run { my ($class) = @ARG; Gtk->init; my $window = $class->new; $window->TOPLEVEL->show; Gtk->main; } sub new { # # This sub will create the UI window my $that = shift; my $class = ref($that) || $that; my $self = { _permitted_fields => \%fields, %fields, _permitted_stubs => \%stubs, %stubs, }; my ($forms, $widgets, $data, $work); # # Create a GtkWindow 'BusFrame' >> BLAH BLAH BLAH - UI construction Perl/Gtk calls # # Return all forms in the constructed UI bless $self, $class; $self->FORM($forms->{'BusFrame'}); $self->TOPLEVEL($self->FORM->{'BusFrame'}); return $self; } ---------------8<----------------------------- This can be subclassed by, for example: ---------------8<----------------------------- package BusForm_Subclass; require 5.000; use English; use strict 'vars', 'refs', 'subs'; BEGIN { # Import our existing signal handler modules use Existing::BusForm_mySUBS; # Now import the UI construction class use Generated::BusForm; use vars qw( @ISA %fields $AUTOLOAD ); # Tell interpreter who we are inheriting from @ISA = qw( BusFrame Existing::BusForm_mySUBS); # Inherit the AUTOLOAD dynamic methods from BusForm *AUTOLOAD = \&BusFrame::AUTOLOAD; } %fields = ( # Insert any extra data access methods that you want to add to # our inherited super-constructor (or overload) USERDATA => undef, VERSION => '9.9.9', ); #====================================================================== #=== These are the overloaded class constructors and so on === #====================================================================== sub new { my $that = shift; # Allow indirect constructor so that we can call eg. # $window1 = BusForm_mySUBS->new; # and then # $window2 = $window1->new; my $class = ref($that) || $that; # Call our super-class constructor to get an object and reconsecrate it my $self = bless $that->SUPER::new(), $class; # Add our own data access methods to the inherited constructor my($element); foreach $element (keys %fields) { $self->{_permitted_fields}->{$element} = $fields{$element}; } @{$self}{keys %fields} = values %fields; return $self; } sub run { my ($class) = @ARG; Gtk->init; my $window = $class->new; $window->USERDATA({ 'Key1' => 'Value1', 'Key2' => 'Value2', 'Key3' => 'Value3', }); $window->TOPLEVEL->show; Gtk->main; } #======================================================================= #==== Below are overloaded signal handlers ==== #======================================================================= >> BLAH BLAH BLAH ---------------8<----------------------------- and the whole thing could be run by for example: perl -e 'use BusForm_Subclass; BusForm_Subclass->run()'; This approach works but I am not sure how 'correct' it is. If you have read this far, thanks again for any advice that you have. Regards, Dermot +---------------------------------------------------------------------+ To unsubscribe from this list, send a message to [EMAIL PROTECTED] with the line "unsubscribe glade-devel" in the body of the message.