Before you even begin writing a publicly consumable Perl/Tk widget, check the Perl/Tk mega-widget home page at http://www.lehigh.edu/sol0/ptk/modlist,[38] where you'll learn about your responsibilities as a module writer. The idea is to stop duplication of effort and coordinate the naming, development, and testing of modules. It's also important to keep the Perl/Tk mailing list ptk@lists.stanford.edu and the news group comp.lang.perl.tk advised of your module. You'll get invaluable feedback that will make your final result more polished.
[38] Originally developed by Graham Barr, the page is now maintained by Achim Bohnet.
Assuming you've followed the protocol and have a pure Perl/Tk widget module ready for distribution, you must register yourself as a CPAN developer and get a CPAN ID. Link to http://www.perl.com/CPAN-local/modules/04pause.html to get registration and upload instructions.
With all the paperwork complete, you need to package your new module so it installs in the standard Perl manner:
% perl Makefile.PL % make % make test % make install
We'll use the NavListbox widget as our example in the next two sections. The first section details packaging the widget for CPAN and the second for ActiveState's Perl Package Manager (PPM).
To begin, create a new, empty distribution directory and copy to it the widget module file, NavListbox.pm. For completeness, we need to populate the distribution directory with at least three more files, as shown in the next section. The files are MANIFEST, Makefile.PL, and test.pl.
Every well-formed Perl module requires a file named Makefile.PL, which is an actual Perl program that describes the module. Perl executes this file, resulting in a generated Makefile that we use to build, test, and install the module.
Now create a file named Makefile.PL, containing these lines:
use ExtUtils::MakeMaker; my $pm = 'NavListbox'; WriteMakefile( NAME => "Tk::$pm", DISTNAME => "Tk-$pm", VERSION_FROM => "$pm.pm", dist => {COMPRESS => 'gzip', SUFFIX => 'gz'}, ($] >= 5.005 ? (ABSTRACT => 'Navigatible Listbox', AUTHOR => 'Flaz T. Bizzo (ftb@xy.zz.y)') : ( ), ), );
This Makefile.PL program stores the module name in a Perl variable, so it's easy to reuse. The WriteMakefile subroutine can take many arguments, fully described in its POD:
% perldoc ExtUtils::MakeMaker
The minimum attributes we require are:
The last two attributes, particularly important for modules destined for a PPM archive, are conditional, because they weren't available prior to Perl 5.005.
To complete our distribution, we need two more files—MANIFEST, which lists all the filenames in the distribution, and test.pl, a Perl program for the make test phase—for a total of four files: NavListbox.pm, Makefile.PL, MANIFEST, and test.pl.
This configuration will likely work, but instead of using ExtUtils::MakeMaker::WriteMakefile, we should use its Tk counterpart, Tk::MMutil::TkExtMakefile.
As it happens, without even resorting to trickery, an improved Makefile.PL program using TkExtMakefile can do several more things:
Create the MANIFEST file automatically.
Create the test.pl file automatically.
Add an optional sample program to widget's User Contributed Demonstrations section. widget is a Perl/Tk program that demonstrates most of the toolkit's capabilities and is installed in your normal Unix or Win32 path. It's a multisection hypertext application that contains a special User Contributed Demonstrations section for highlighting nonstandard toolkit features. You can use the following special Makefile.PL to include a special demonstration of your new widget. For our purposes, this optional fifth file—the "widget contributed" (widtrib) demonstration file—is included.
Here's the widtrib file, navtest.pl:
# A NavListbox sample program. use Tk; use Tk::NavListbox; use strict; my $mw = MainWindow->new; my $nlb = $mw->NavListbox->pack; for (qw/one two three four five six seven eight none ten/) { $nlb->insert('end', $_); } MainLoop;
Our new Makefile.PL first writes the MANIFEST file containing the names of the four archive files plus the widtrib demonstration file, then writes test.pl after first substituting our module's name in the template.
# A generic Makefile.PL file for any pure Perl/Tk mega-widget. Set # $pm to the name of the Perl module, and update %widinfo. Leave # $widtrib undefined unless you have an addition for widget's User # Contributed Demonstrations section. # # This program creates the MANIFEST and test.pl files, then invokes # MakeMaker to create the Makefile. sol0@Lehigh.EDU, 2001/01/01 use Tk::MMutil; use vars qw/$pm $widinfo $widtrib %widtrib/; $pm = 'NavListbox'; # widget Class name %widinfo = ( # PPM widget information ABSTRACT => 'Navigatible Listbox', AUTHOR => 'Nancy Walsh (nw@xy.zz.y)', ); $widtrib = 'navtest.pl'; # widtrib demo file name print "Writing MANIFEST for Tk::$pm\n"; open MANIFEST, ">MANIFEST" or die "Cannot open MANIFEST: $!"; print MANIFEST <<"end-of-manifest"; MANIFEST Makefile.PL $pm.pm test.pl end-of-manifest print MANIFEST "$widtrib\n" if $widtrib; close MANIFEST or die $!; print "Writing test.pl for Tk::$pm\n"; open TEST, ">test.pl" or die "Cannot open test.pl: $!"; while (<DATA>) { s/NavListbox/$pm/o; print TEST; } close TEST or die $!; %widtrib = ($widtrib => "\$(INST_ARCHLIB)/Tk/demos/widtrib/$widtrib") if $widtrib; Tk::MMutil::TkExtMakefile( NAME => "Tk::$pm", DISTNAME => "Tk-$pm", VERSION_FROM => "$pm.pm", PM => {"$pm.pm" => "\$(INST_LIBDIR)/$pm.pm", %widtrib}, dist => {COMPRESS => 'gzip', SUFFIX => 'gz'}, ($] >= 5.005 ? %widinfo : ( )), ); __DATA__ #!perl -w use Test; use strict; BEGIN { plan tests => 12 }; eval { require Tk; }; ok($@, "", "loading Tk module"); my $mw; eval {$mw = Tk::MainWindow->new( );}; ok($@, "", "can't create MainWindow"); ok(Tk::Exists($mw), 1, "MainWindow creation failed"); eval { $mw->geometry('+10+10'); }; my $w; my $class = 'NavListbox'; print "Testing $class\n"; eval "require Tk::$class;"; ok($@, "", "Error loading Tk::$class"); eval { $w = $mw->$class( ); }; ok($@, "", "can't create $class widget"); skip($@, Tk::Exists($w), 1, "$class instance does not exist"); if (Tk::Exists($w)) { eval { $w->pack; }; ok ($@, "", "Can't pack a $class widget"); eval { $mw->update; }; ok ($@, "", "Error during 'update' for $class widget"); eval { my @dummy = $w->configure; }; ok ($@, "", "Error: configure list for $class"); eval { $mw->update; }; ok ($@, "", "Error: 'update' after configure for $class widget"); eval { $w->destroy; }; ok($@, "", "can't destroy $class widget"); ok(!Tk::Exists($w), 1, "$class: widget not really destroyed"); } else { for (1..5) { skip (1,1,1, "skipped because widget couldn't be created"); } } 1;
So now we have three files, NavListbox.pm, navtest.pl, and Makefile.PL, in an otherwise empty directory. Type this:
% perl Makefile.PL % make
This automatically creates MANIFEST and test.pl for us. Now type this:
% make test
This creates the final distribution file, Tk-NavListbox-1.0.tar.gz, which you should then unpack and test as if you had just retrieved in from CPAN. If all is well, follow the CPAN upload instructions.
If you're creating a PPM archive, we assume you're running in a Win32 environment, which usually lacks make, tar, and gzip programs. So first get nmake from ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe and gzip from http://www.itribe.net/virtunix.
Create the four distribution files (NavListbox.pm, Makefile.PL, MANIFEST, and test.pl) as described in the previous section and build the distribution directory, blib:
% perl Makefile.PL % nmake
Then pack the directory into an archive:
% tar -cvpf Tk-NavListbox-1.0.tar blib % gzip --best Tk-NavListbox-1.0.tar
You now have an archive called (hopefully) Tk-NavListbox-1.0.tar.gz. Generate the PPD file:
% nmake ppd
You have to edit the resulting PPD file and add the location of the package archive into <CODEBASE HREF=""/>. The location is relative to the PPD file.
And that's it with regard to Perl/Tk mega-widgets. If you're interested in C-level widget information, check out Chapter 21, "C Widget Internals".
Copyright © 2002 O'Reilly & Associates. All rights reserved.