start page | rating of books | rating of authors | reviews | copyrights

Book HomeMastering Perl/TkSearch this book

14.2. The Perl/Tk Class Hierarchy

Mega-widgets are hierarchical in nature. Base classes are combined to create new classes of ever greater functionality and sophistication.

The following statement creates a Label widget as a child of the MainWindow, $mw, and stores a reference to it in the Perl variable $l:

my $l = $mw->Label;

In object-oriented lingo, it instantiates (makes an instance of) an object of class Tk::Label. If we don't know an object's class, we can determine it using the ref function:

print "l = $l, class = ", ref $l, "\n";

l = Tk::Label=HASH(0x822b3d0), class = Tk::Label

We see that in reality, $l is a reference to a hash that has been bless ed into the package Tk::Label. What we don't know is where this class exists in the overall Tk class hierarchy. This useful bit of information not only tells us the path Perl follows when looking up object methods but also a widget's class relationship with other widgets.

We can write a program that uses an HList widget (fully described in Chapter 18, " A Tk Interface Extension Tour") to graph a depth-first traversal of any widget's @ISA array. The program, isa, accepts a Tk class name as input via an Entry widget, then recursively calls isa_tree. This subroutine adds the class name to the HList tree, loads the module file so the symbol table is available, determines the module's base classes by evaluating the new module's @ISA array, and calls itself recursively as required.

use Tk;
use Tk::widgets qw/HList/;
use subs qw/isa_tree/;
use strict;

my $mw = MainWindow->new;
my $instance = 0;

my $hl = $mw->Scrolled(qw/HList
    -separator | -indent 35 -scrollbars sw/
)->pack(qw/-fill both -expand 1/);

my $m = 'Tk::Dialog';
my $e = $mw->Entry(-textvariable => \$m)->pack;
my $cb = sub {
    my $mod = shift->get;
    isa_tree $hl, $mod, $mod . $instance;
};
$e->bind('<Return>' => $cb);
$e->focus;

MainLoop;

sub isa_tree {
    my($h, $class, $path) = @_;

    $h->add($path, -text => $class);
    (my $file = $class) =~ s\::\/\g;
    require "$file.pm";

    foreach my $base_class (eval "\@${class}::ISA") {
        isa_tree $h, $base_class, "$path|$base_class";
    }
} # end isa_tree

Figure 14-3 shows the class tree for a Label widget, which is typical of most core Perl/Tk widgets. Its immediate base class is Tk::Widget, a class module that provides over a hundred subroutines and methods common to all widgets, two of which are ClassInit and Populate. Since Tk::Widget is the "lowest base class," Tk::Widget::ClassInit and Tk::Widget::Populate, both empty subroutines, are invoked if and only if they are not overridden in a subclass. They act as safety valves, ensuring that every Perl/Tk widget has Populate and ClassInit methods.

Figure 14-3

Figure 14-3. Class hierarchy for a Label widget

For historical reasons, Tk.pm acts as a base class for Tk::Widget and as an Exporter module, where it provides over 60 subroutines and methods.

Figure 14-4 shows the class hierarchy for our Frame-based LabOptionmenu widget. When Populate and ClassInit are called on a LabOptionmenu widget, Perl first finds the methods in class Tk::LabOptionmenu. Each of these methods then passes the call to a superclass. For Populate, we know the call is satisfied by Tk::Frame::Populate, where the Label configuration specifications are generated. But Tk::Frame doesn't provide a ClassInit subroutine, so Perl keeps traversing the @ISA array until it finds the safety valve, Tk::Widget::ClassInit.

Figure 14-4

Figure 14-4. Class hierarchy for a LabOptionmenu widget

Note the special class Tk::Derived. It's an important base class for mega-widgets, because it provides more than 15 methods, including configure and cget, specially designed to make mega-widgets behave like core Tk widgets. Tk::Derived must be available, somewhere, in every mega-widget's @ISA tree.

Figure 14-5 shows that Dialog is a subclass of DialogBox, a Toplevel-based composite. We see several familiar classes it's based upon. We might even hazard to guess that a Toplevel is basically a Frame with some window manager attributes thrown in!

Figure 14-5

Figure 14-5. Class hierarchy for a Dialog widget



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.