Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

A Tk::Wizard Framework

by dhable (Monk)
on Jan 17, 2002 at 00:56 UTC ( [id://139336]=sourcecode: print w/replies, xml ) Need Help??
Category: GUI Programming
Author/Contact Info dhable
Description: This is my first attempt at writing a robust Perl library and I would like some honest feedback on how I could make this better. It's mainly a class that creates a GUI wizard control in Tk.

######################################################################
+#################
#
# Class:     Tk::Wizard
#
# Description:    The Tk::Wizard class is a Tk component that allows u
+sers to create a 
#               Microsoft style application wizard without having to w
+rite the code to 
#               manage the wizard framework components, like event dis
+patching, etc.
#
######################################################################
+#################



package Tk::Wizard;

use SelfLoader;
use Tk;
use Tk::JPEG;
use Tk::Text;
use strict;
no strict 'refs';


######################################################################
+################################
#
# Method:    new
#
# Description:    Creates a new object of type Tk::Wizard and sets the
+ default state
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub new($) {
    my $invocant = shift;
    my $class = ref( $invocant) || $invocant;
        my $self = { # required for GUI operation
             hWin             => $_[0],

             # configuration parameters
                     title             => "Generic Wizard",
                     filename             => "image.jpg",

                     # event handling references
                     preNextButtonAction    => undef,
                     postNextButtonAction    => undef,
                     
                     prePrevButtonAction     => undef,
                     postPrevButtonAction    => undef,
                     
                     preHelpButtonAction     => undef,
                     helpButtonAction        => undef,
                     postHelpButtonAction    => undef,
                     
                     preFinishButtonAction   => undef,
                     finishButtonAction      => undef,
                     postFinishButtonAction  => undef,
                      
                     preCancelButtonAction   => undef,
                     preCloseWindowAction    => undef,

                     # wizard page control list and ptr
                     wizardPageList          => [],    # ref to empty 
+array
                     wizardPagePtr           => 0,

             # internally used to track the wizard page being shown
             wizardFrame         => ""
                   };
    return bless( $self, $class);
} # end of sub new


######################################################################
+################################
#
# Method:    setActionEventHandlers
#
# Description:    Allows the documented set of actions to be overwritt
+en to hook the Tk::Wizard
#               framework into the application. While no handler must 
+be overwritten, it is
#               very useful to overwrite the helpButtionAction and the
+ finishButtonAction
#               event handlers.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub setActionEventHandlers {
   my $self = shift;
   my %newHandlers = ( @_ );

   foreach( keys %newHandlers) {
      $self->{"$_"} = $newHandlers{$_};
   } # end of foreach
} # end of setActionEventHandlers


######################################################################
+################################
#
# Method:    setParamaters
#
# Description:    Provide useful definitions for the two main paramete
+rs - title and filename. title
#               refers to the scalar string that will be printed on th
+e wizard's title bar. filename
#               is the location and name of a JPEG file that should be
+ displayed on the left side of
#               the wizard.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub setParameters {
   my $self = shift;
   my %newParams = ( @_ );

   foreach( keys %newParams) {
      $self->{"$_"} = $newParams{"$_"};
   } # end of foreach
} # end of setParameters


######################################################################
+################################
#
# Method:      addWizardPage
#
# Description: Puts the passed in wizard page at the end of the wizard
+ page list.
#
# Parameters:  $page    = The wizard page that should be added to the 
+end of the wizard list.
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub addWizardPage {
   my ($self, $page) = @_;
   push @{$self->{wizardPageList}}, $page;
} # end of sub addWizardPage


######################################################################
+################################
#
# Method:    currentPage
#
# Description:    Returns the page number that is currently being disp
+layed. Page counting starts with 1.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub currentPage {
    my($self) = @_;
    return ($self->{wizardPagePtr} + 1);
} # end of sub currentPage
1;

######################################################################
+##############
# Functions below this level are only loaded on demand. This gives the
+ appearance of
# faster load times. See module SelfLoader for details.
######################################################################
+##############
__DATA__

sub parent {
    my ($self) = @_;
    return $self->{hWin};
}

######################################################################
+################################
#
# Method:    wpFrame
#
# Description:    This returns a Tk::Frame object that is a child of t
+he Wizard control. It should be
#         used when creating wizard pages since some padding parameter
+s are applied to it by
#         the wizard control.
#
# Parameters:    N/A
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub wpFrame {
    my ($self) = @_;

    my $frame = $self->{hWin}->Frame( -width => 400, -height => 400);
    $frame->packPropagate( 0);
    return $frame;
} # end of wpFrame


######################################################################
+################################
#
# Method:      Show
#
# Description: The Show method actually creates all of the necessary c
+omponents on the window that is
#              set in the new method. It is important that Wizard appl
+ications that use MainWindow for
#              drawing the Wizard also dispatch MainLoop after the Sho
+w method.
#
# Parameters:  None
#
# Exceptions:  N/A in this release
#
######################################################################
+################################
sub Show {
        my ($self) = @_;

    #
    # builds the buttons on the bottom of thw wizard
    #
    my $buttonPanel = $self->{hWin}->Frame();
    $buttonPanel->Button( -text => "Cancel", 
                              -command => [ \&CancelButtonEventCycle, 
+$self, $self->{hWin}], 
                              -width => 10
                            ) ->pack( -side => "right", -expand => 0);

    $self->{nextButtonRef} = $buttonPanel->Button( -text => "Next >", 
                           -command => [ \&NextButtonEventCycle, $self
+ ],
                           -width => 10
                                             )->pack( -side => "right"
+, -expand => 0);

    $self->{prevButtonRef} = $buttonPanel->Button( -text => "< Previou
+s", 
                                               -command => [ \&PrevBut
+tonEventCycle, $self ], 
                           -width => 10,
                           -state => "disabled"
                         )->pack( -side => "right", -expand => 0);

    $buttonPanel->Button( -text => "Help", 
                              -command => [ \&HelpButtonEventCycle, $s
+elf ], 
                              -width => 10
                            )->pack( -side => 'left', -anchor => 'w');

    $buttonPanel->pack( -side => "bottom", -fill => 'x', -pady => 4, -
+padx => 4);


    #
    # builds the image on the left side of the wizard
    #
    $self->{hWin}->Photo( "sidebanner", -format => "jpeg", -file => $s
+elf->{filename});
    $self->{hWin}->Label( -image => "sidebanner")->pack( -side => "lef
+t", -anchor => "w");


    #
    # This populates the wizard page panel on the side of the screen.
    #
        $self->{wizardFrame} = 
            $self->{wizardPageList}->[($self->{wizardPagePtr})]->()->p
+ack( -side => "top", -expand => 0);


    #
    # setup the containing window to match the criteria for a wizard w
+idget
    #
    $self->{hWin}->configure( -title => $self->{title});
    $self->{hWin}->resizable( 0, 0);        # forbid resize
    $self->{hWin}->withdraw;                # position in screen cente
+r
    $self->{hWin}->Popup;
    $self->{hWin}->transient;               # forbid minimize
        $self->{hWin}->protocol( WM_DELETE_WINDOW => [ \&CloseWindowEv
+entCycle, $self, $self->{hWin}]);
} # end of sub Show


######################################################################
+################################
#
# Method:       dispatch
#
# Description:  Thin wrapper to dispatch event cycles as needed
#
# Parameters:    The dispatch function is an internal function used to
+ determine if the dispatch back reference
#         is undefined or if it should be dispatched. Undefined method
+s are used to denote dispatchback
#         methods to bypass. This reduces the number of method dispatc
+hs made for each handler and also
#         increased the usability of the set methods above when trying
+ to unregister event handlers.
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub dispatch {
    my ($handler) = @_;
    if( defined $handler) { return !($handler->());}
    return 0;
} # end of sub dispatch


######################################################################
+################################
#
# Method:      NextButtonEventCycle
#
# Description: Runs the complete view of the action handler cycle for 
+the "Next>" button on the
#              wizard button bar. This includes dispatching the preNex
+tButtonAction and
#              postNextButtonAction handler at the apporprate times.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub NextButtonEventCycle {
   my ($self) = @_;
   if( dispatch( $self->{preNextButtonAction})) { return;}

   # advance the wizard page pointer and then adjust the navigation bu
+ttons.
   # readraw the frame when finished to get changes to take effect.
   $self->{wizardPagePtr}++;
   $self->{wizardPagePtr} = $#{$self->{wizardPageList}} if( $self->{wi
+zardPagePtr} >= $#{ $self->{wizardPageList}});

   if( $self->{nextButtonRef}->cget( -text) eq "Finish") {
      if( dispatch( $self->{finishButtonAction})) { return; }
      $self->CloseWindowEventCycle();
   }
   $self->{prevButtonRef}->configure( -state => "normal");
   $self->{nextButtonRef}->configure( -text => "Finish") if( $self->{w
+izardPagePtr} == $#{ $self->{wizardPageList}});
   $self->redrawWizardPage;

   if( dispatch( $self->{postNextButtonAction})) { return; }
} # end of sub NextButtonEventCycle


######################################################################
+################################
#
# Method:      PrevButtonEventCycle
#
# Description: Runs the complete view of the action handler cycle for 
+the "<Previous" button on the
#              wizard button bar. This includes dispatching the prePre
+vButtonAction and
#              postPrevButtonAction handler at the apporprate times.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub PrevButtonEventCycle {
   my ($self) = @_;
   if( dispatch( $self->{prePrevButtonAction})) { return; }


   # move the wizard pointer back one position and then adjust the nav
+igation buttons
   # to reflect any state changes. Don't fall off end of page pointer
   $self->{wizardPagePtr}--;
   $self->{wizardPagePtr} = 0 if( $self->{wizardPagePtr} < 0);
   
   $self->{nextButtonRef}->configure( -text => "Next >");
   $self->{prevButtonRef}->configure( -state => "disabled") if( $self-
+>{wizardPagePtr} == 0);
   $self->redrawWizardPage;

   if( dispatch( $self->{postPrevButtonAction})) { return; }
} # end of sub PrevButtonEventCycle


######################################################################
+################################
#
# Method:      HelpButtonEventCycle
#
# Description: This generates all of the events required when the Help
+ button is clicked. This runs
#              through the pre event handler, the event handler and th
+en the post event handler. If
#              no event handlers are defined, the method does nothing.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub HelpButtonEventCycle {
   my ($self) = @_;
   if( dispatch( $self->{preHelpButtonAction})) { return; }
   if( dispatch( $self->{helpButtonAction})) { return; }
   if( dispatch( $self->{postHelpButtonAction})) { return; }
} # end of sub HelpButtonEventCycle


######################################################################
+################################
#
# Method:      CancelButtonEventCycle
#
# Description: This generates all of the necessary events reqruied for
+ a good Wizard control when
#              the cancel button is clicked. This involves dispatching
+ the preCancelButtonAction handler
#              and then activating the CloseWindowEventCycle to run th
+rough the process of closing
#              the window.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub CancelButtonEventCycle {
   my ($self, $hGUI) = @_;
   if( dispatch( $self->{preCancelButtonAction})) { return;}
   $self->CloseWindowEventCycle( $hGUI);
} # end of sub CancelButtonEventCycle


######################################################################
+################################
#
# Method:      CloseWindowEventCycle
#
# Description: This generates all of the necessary events required for
+ a good Wizard control when
#              the Window is about to be closed. This involves dispatc
+hing the preCloseWindowAction handler
#              and then destroying the reference to the Window control
+.
#
# Parameters:    None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub CloseWindowEventCycle {
   my ($self, $hGUI) = @_;
   if( dispatch( $self->{preCloseWindowAction})) { return;}
   $hGUI->destroy;
} # end of sub CloseWindowEventCycle


######################################################################
+################################
#
# Method:      redrawWizardPage
#
# Description: Update the wizard page panel by unpacking the existing 
+controls and then repacking.
#              This allows updates to the page pointer to become visib
+le.
#
# Parameters:  None
#
# Exceptions:    N/A in this release
#
######################################################################
+################################
sub redrawWizardPage {
   my ( $self) = @_;

   $self->{wizardFrame}->packForget;
   $self->{wizardFrame} = $self->{wizardPageList}->[$self->{wizardPage
+Ptr}]->()->pack( -side => "top");
} # end of sub redrawWizardPagePanel


#############################
# End of Package Tk::Wizard #
#############################
1;
__END__
=head1 NAME

Tk::Wizard - GUI Wizard Framework

=head1 SYNOPSIS


   use Tk::Wizard;
  
   my $wizard = new Wizard( new MainWindow);
   $wizard->addWizardPage( \&createPage1);
   $wizard->addWizardPage( \&createPage2);
   $wizard->addWizardPage( \&createPage3);
   $wizard->Show();
   
   MainLoop;

=head1 DESCRIPTION

The Tk::Wizard class automates a large part of creating a program wiza
+rd to collect information and then
perform some complex task based upon the answers and information gathe
+red from the user. The wizard feel
is largly based upon the Microsoft wizard style that appeared in produ
+cts like Office 95 and Office 97.

=head1 METHODS

=head2 Tk::Wizard-E<gt>new( @args)

Creates a new instance of the Tk::Wizard object. The @args list is a h
+ash list of the different
options that can be specified for the class. These include:

Parameters:

   -title => This is the title that will be displayed in the Windows t
+itle bar
   
   -filename => This is the path and name of a JPEG file that will be 
+displayed on the right side
                of the screen.

Action Event Handlers:
                
   -preNextButtonAction => This is a reference to a function that will
+ be dispatched before the Next
                           button is processed.
                           
   -postNextButtonAction => This is a reference to a function that wil
+l be dispatched after the Next
                            button is processed.
                            
   -prePrevButtonAction => This is a reference to a function that will
+ be dispatched before the Previous
                           button is processed.
                           
   -postPrevButtonAction => This is a reference to a function that wil
+l be dispatched after the Previous
                            button is processed.
                            
   -preHelpButtonAction => This is a reference to a function that will
+ be dispatched before the Help
                           button is processed.
                           
   -helpButtonAction => This is a reference to a function that will be
+ dispatched to handle the Help
                        button action.
                            
   -postHelpButtonAction => This is a reference to a function that wil
+l be dispatched after the Help
                            button is processed.

   -preFinishButtonAction => This is a reference to a function that wi
+ll be dispatched before the Finish
                             button is processed.
                             
   -finishButtonAction => This is a reference to a funciton that will 
+be dispatched to handle the Finish
                          button action.
                          
   -postFinishButtonAction => This is a reference to a function that w
+ill be dispatched after the Finish
                              button is processed.
                              
   -preCancelButtonAction => This is a reference to a function that wi
+ll be dispatched before the Cancel
                             button is processed.
                             
   -preCloseWindowAction => This is a reference to a funciton that wil
+l be dispatched before the window
                            is issued a close command.

    See the section Action Event Handlers for more details.
                                               
=head2 Tk::Wizard-E<gt>setActionEventHandlers( @args)

This method can be used to set or change the action event handler func
+tions of a Tk::Wizard instance.
The @args list accepts any Action Event Handler value pairs that could
+ be passed into the new method.

See the section Action Event Handlers for more details.

=head2 Tk::Wizard-E<gt>setParameters( @args)

This method can be used to set or change the parameters of a Tk::Wizar
+d instance. The @args list
accepts any Parameter value pairs that could be passed into the new me
+thod.

=head2 Tk::Wizard-E<gt>Show()

This method must be dispatched before the Wizard will be displayed. 

=head2 Tk::Wizard-E<gt>addWizardPage( $page)

This method is used to add a Wizard page to the wizard. The $page para
+meter must be a Tk::Frame object.
The pages are stored and will be displayed in the order that they were
+ added to the Wizard control.

=head2 Tk::Wizard-E<gt>currentPage()

This returns the index of the page that is currently shown. Pages are 
+indexed starting at 0 with the
first page that is associated with the wizard through the addWizardPag
+e method.

=head2 Tk::Wizard-E<gt>wpFrame()

This returns a wizard page frame. This method should be called when th
+e user of the wizard wants to
build the page specific controls.

=head2 Tk::Wizard-E<gt>parent

This returns the parent Tk widget that was used to create the wizard a
+nd all of the controls. This is
defined as part of the new method.

=head1 Action Event Handlers

The action event handler functions should not accept and parameters an
+d return a TRUE or FALSE variable. If
the remainder of the action should continue a TRUE value is returned. 
+If a FALSE value is returned, execution
of the event handler stops. This can be used to prompt the user if the
+y want to quit and take action based upon
the input.

=head1 SUPPORT

A list of the current development efforts can be found at 
http://www.uwm.edu/~dthable/perl

=head1 COPYRIGHT

Copyright (c) 2002 Daniel T. Hable

Permission is hereby granted, free of charge, to any person obtaining 
+a copy of this software and associated 
documentation files (the "Software"), to deal in the Software without 
+restriction, including without limitation 
the rights to use, copy, modify, merge, publish, distribute, sublicens
+e, and/or sell copies of the Software, 
and to permit persons to whom the Software is furnished to do so, subj
+ect to the following conditions:

The above copyright notice and this permission notice shall be include
+d in all copies or substantial portions of 
the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES
+S OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ AND NONINFRINGEMENT. IN NO EVENT SHALL 
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR O
+THER LIABILITY, WHETHER IN AN ACTION OF 
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WIT
+H THE SOFTWARE OR THE USE OR OTHER 
DEALINGS IN THE SOFTWARE.

=cut
Replies are listed 'Best First'.
Re: A Tk::Wizard Framework
by Anonymous Monk on Nov 14, 2002 at 12:26 UTC
    Have you seen http://www1.clearlight.com/~oakley/tcl/tkwizard/index.html ?
      How do you run the program? I've downloaded both the .zip and the .tar
Re: A Tk::Wizard Framework
by Anonymous Monk on Jun 07, 2013 at 00:21 UTC
    For anyone interested, there is now a Tk::Wizard based/inspired by this on CPAN :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://139336]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (2)
As of 2024-12-09 16:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which IDE have you been most impressed by?













    Results (54 votes). Check out past polls.