NAME
Defining a new composite widget class
SYNOPSIS
package Whatever;
@ISA = qw(Tk::Frame); # or Tk::Toplevel
Tk::Widget->Construct('Whatever');
sub Populate
{
my ($cw,$args) = @_;
my $flag = delete $args->{-flag};
if (defined $flag)
{
# handle -flag => xxx which can only be done at create time
# the delete above ensures that new() does not try and
# do $cw->configure(-flag => xxx)
}
$w = $cw->Component(...);
$cw->Delegates(...);
$cw->ConfigSpecs('-cursor' => [SELF,cursor,Cursor,undef],
'-something' => [METHOD,dbName,dbClass,'default'],
'-text' => [$label,dbName,dbClass,'default'],
'-heading' => [Tk::Config->new($head,-text),heading,Heading,'My Heading']
);
}
sub something
{
my ($cw,$value) = @_;
if (@_ > 1)
{
# set it
}
return # current value
}
1;
__END__
DESCRIPTION
The intention behind a composite is to create a higher-level widget, sometime called a "super-widget". Most often, a composite will be built upon other widgets by using them, as opposed to specializing on them. For example, the supplied composite widget LabEntry
is made of an Entry
and a Label
; it is neither a kind-of Label
nor is it a kind-of Entry
.
Most of the work of a composite widget consist in creating subwidgets, arrange to dispatch configure options to the proper subwidgets and manage composite-specific configure options.
Composite widget creation
Since pTk
is heavilly using an object-oriented approach, it is no suprise that creating a composite goes through a new()
method. However, the composite does not normally define a new()
method itself: it is usually sufficient to simply inherit it from Tk::Widget
.
This is what happens when the composite use
@ISA = qw(Tk::Frame); # or Tk::Toplevel
to specify its inheritance chain. To complete the initialisation of the widget, it must call the Construct
method from class Widget
. That method accepts the name of the new class to create, i.e. the package name of your composite widget:
Tk::Widget->Construct('Whatever');
Here, Whatever
is the package name (aka the widget's class). This will define a constructor method for Whatever
, named after the widget's class. Instanciating that composite in client code would the look like:
$top = MainWindow->new(); # Creates a top-level main window
$cw = $top->Whatever(); # Creates an instance of composite widget
# 'Whatever'
Whenever a composite is instanciated in client code, Tk::Widget::new()
will be invoked via the widget's class constructor. That new()
method will call
$cw->InitObject(\%args);
where %args
is the arguments passed to the widget's constructor. Note that InitObject
receives a reference to the hash array containing all arguments.
For composite widgets that needs an underlying frame, InitObject
will typically be inherited from Tk::Frame
, that is, no method of this name will appear in the composite package. For composites that don't need a frame, InitObject
will typically be defined in the composite class (package). Compare the LabEntry
composite with Optionmenu
: the former is Frame
based while the latter is Widget
based.
In Frame
based composites, Tk::Frame::InitObject()
will call Populate()
, which should be defined to create the characteristic subwidgets of the class.
Widget
based composites don't need an extra Populate
layer; they typically have their own InitObject
method that will create subwidgets.
Creating Subwidgets
Subwidget creation happens usually in Populate()
(Frame
based) or InitObject()
(Widget
based). The composite usually calls the subwidget's constructor method either directly, for "private" subwidgets, or indirectly through the Component
method for subwidgets that should be advertised to clients.
Populate
may call Delegates
to direct calls to methods of chosen subwidgets. For simple composites, typically most if not all methods are directed to a single subwidget - e.g. ScrolledListbox
directs all methods to the core Listbox
so that $composite->get(...) calls $listbox->get(...).
Further steps for Frame
based composites
Populate
should also call ConfigSpecs()
to specify the way that configure-like options should be handled in the composite. Once Populate
returns, method Tk::Frame::ConfigDefault
walks through the ConfigSpecs
entries and populates %$args hash with defaults for options from X resources (.Xdefaults, etc).
When InitObject()
returns to Tk::Widget::new()
, a call to $cw->configure(%$args) is made which sets *all* the options.