package Tk::MyNewWidget;
For composite widget classes:
use base qw/ Tk::container /; # where container is Frame or Toplevel
For derived widget classes:
use base qw/ Tk::Derived Tk::DerivedWidget /;
Install the new widget in Tk's namespace and establish class and instance constructors.
Construct Tk::Widget 'MyNewWidget';
sub ClassInit { my ($self, $args) = @_; ... }
sub Populate { my ($self, $args) = @_; ... }
There are two kinds of mega-widgets:
A composite widget is composed with one or more existing widgets. The composite widget looks to the user like a simple single widget. A well known example is the file selection box.
A derived widget adds/modifies/removes properties and methods from a single widget (this widget may itself be a mega-widget).
Usage:
$self->Advertise(name=>$widget);
Gives a subwidget $widget of the mega-widget $self the name name. One can retrieve the reference of an advertised subwidget with the Subwidget method.
Comment: Mega-Widget Writers: Please make sure to document the advertised widgets that are intended for public use. If there are none, document this fact, e.g.:
=head1 ADVERTISED WIDGETS None.
Usage:
$self->Callback(-option ?,args ...?);
Callback executes the callback defined with $self->ConfigSpecs(-option, [CALLBACK, ...]); If args are given they are passed to the callback. If -option is not defined it does nothing.
Usage:
sub ClassInit { my ($class, $mw) = @_; ... }
ClassInit is called once for each MainWindow just before the first widget instance of a class is created in the widget tree of MainWindow.
ClassInit is often used to define bindings and/or other resources shared by all instances, e.g., images.
Examples:
$mw->bind($class,"<Tab>", sub { my $w = shift; $w->Insert("\t"); $w->focus; $w->break}); $mw->bind($class,"<Return>", ['Insert',"\n"]); $mw->bind($class,"<Delete>",'Delete');
Notice that $class is the class name (e.g. Tk::MyText) and $mw is the mainwindow.
Don't forget to call $class->SUPER::ClassInit($mw) in ClassInit.
Usage:
$cw->Component('Whatever', 'AdvertisedName', -delegate => ['method1', 'method2', ...], ... more widget options ..., );
Component does several things for you with one call:
o Advertises it with a given name (overridden by 'Name' option)
o Delegates a set of methods to this widget (optional)
Example:
$cw->Component('Button', 'quitButton', -command => sub{$mw->'destroy'});
Usage:
$cw->ConfigSpecs( -option => [ where, dbname, dbclass, default], ..., DEFAULT => [where], );
Defines the options of a mega-widget and what actions are triggered by configure/cget of an option (see Tk::ConfigSpecs and Tk::Derived for details).
Usage:
Construct baseclass 'Name';
Construct declares the new widget class so that your mega-widget works like normal Perl/Tk widgets.
Examples:
Construct Tk::Widget 'Whatever'; Construct Tk::Menu 'MyItem';
First example lets one use $widget->Whatever to create new Whatever widget.
The second example restricts the usage of the MyItem constructor method to widgets that are derived from Menu: $isamenu->MyItem.
sub CreateArgs { my ($package, $parent, $args) = @_; ...; return @newargs; }
$package is the package of the mega-widget (e.g., Tk::MyText, $parent the parent of the widget to be created and $args the hash reference to the options specified in the widget constructor call.
Don't forget to call $package->SUPER::CreateArgs($parent, $args) in CreateArgs.
Usage:
$cw->Delegates( 'method1' => $subwidget1, 'method2' => 'advertived_name', ..., 'Construct' => $subwidget2, 'DEFAULT' => $subwidget3, );
The 'Construct' delegation has a special meaning. After 'Construct' is delegated all Widget constructors are redirected. E.g. after
$self->Delegates('Construct'=>$subframe);
a $self->Button does really a $subframe->Button so the created button is a child of $subframe and not $self.
Comment: Delegates works only with methods that $cw does not have itself.
Defines construction and interface of derived widgets.
Usage:
sub InitObject { my ($derived, $args) = @_; ... }
where $derived is the widget reference of the already created baseclass widget and $args is the reference to a hash of -option-value pairs.
InitObject is almost identical to Populate method. Populate does some more 'magic' things useful for mega-widgets with several widgets.
Don't forget to call $derived->SUPER::InitObject($args) in InitObject.
Usage:
$widget->OnDestroy(callback);
OnDestroy installs a callback that's called when a widget is going to to be destroyed. Useful for special cleanup actions. It differs from a normal destroy in that all the widget's data structures are still intact.
Comment: This method could be used with any widgets not just for mega-widgets. It's listed here because of its usefulness.
Usage:
sub Populate { my ($self, $args) = @_; ... }
where $self is the widget reference of the already created baseclass widget and $args is the reference to a hash of -option-value pairs.
Most the other support function are normally used inside the Populate subroutine.
Don't forget to call $cw->SUPER::Populate($args) in Populate.
Usage:
$hashref = $self->privateData();
$another = $self->privateData(unique_key|package);
@subwidget = $cw->Subwidget();
$subwidget = $cw->Subwidget(name);
@subwidget = $cw->Subwidget(name ?,...?);
Returns the widget reference(s) of the subwidget known under the given name(s). Without arguments, return all known subwidgets of $cw. See Advertise method how to define name for a subwidget.
Comment: Mega-Widget Users: Use Subwidget to get only documented subwidgets.
Some of the standard options use a resource date base class that is not equal to the resource database name. E.g.,
Switch: Name: Class: -padx padX Pad -activerelief activeRelief Relief -activebackground activeBackground Foreground -status undef undef
One should do the same when one defines one of these options via ConfigSpecs.
Redirecting methods to a subwidget with Delegate can only work if the base widget itself does have a method with this name. Therefore one can't ``delegate'' any of the methods listed in Tk::Widget. A common problematic method is bind. In this case one as to explicitely redirect the method.
sub bind { my $self = shift; my $to = $self->privateData->{'my_bind_target'}; $to->bind(@_); }
Graham Barr wrote: ... It is probably more private than most people think. Not all calls to privateData will return that same HASH reference. The HASH reference that is returned depends on the package it was called from, a different HASH is returned for each package. This allows a widget to hold private data, but then if it is sub-classed the sub-class will get a different HASH and so not cause duplicate name clashes.
But privateData does take an optional argument if you want to force which HASH is returned.
Scrolled(Kind,...) constructor can not be used with Composite. One has to use $cw->Composite(ScrlKind => 'name', ...);