Side of Software
|
|
Wizard Library TutorialTable of ContentsIntroductionMost user-friendly applications use wizards to step the user through difficult or critical tasks. Such a task may, for example, install software, create a user account, or export data to a file. Wizards make these tasks easier by requesting one piece of information at a time rather than overwhelming users with all information at once. In addition, wizards often give users the opportunity to verify their input, which leads to fewer errors and a more enjoyable user experience.
The core Java libraries do not provide high-level support for wizards. As a result, developers either implement their own wizards or resort to using an overcrammed traditional dialog. The Wizard Library provides a framework for which to create wizards. It leads to a common appearance and behavior not only within an application but also across applications. By default, the wizards in this library follow the guidelines set forth by the JavaTM Look and Feel Design Guidelines: Advanced Topics by Sun Microsystems, Inc.
The Wizard Library does not provide content for the wizard’s pages. It is not an application that generates wizards for you, such as InstallShield or InstallAnywhere. Rather, it is a general-purpose library that allows you—through programming—to create wizards for any task. You can certainly use it to create an installation wizard, but it is your responsibility to provide the appropriate page content and wizard task.
Before you start using this library, you should download and include on your classpath the jar file of the Java Look and Feel Graphics Repository. It is available free-of-charge here. Without this resource, your wizards will not display any button icons. The JWizard ComponentThe library includes
The side panel, if one exists, is often a graphic, a list of steps, or a textual source of additional help. For more information on the side panel, see Side Panel.
The page panel is the editable area in which the user inputs information needed to carry out the wizard’s task. The wizard model provides the content of this panel, which changes as the user steps through the pages. For more information on the page panel, see The Wizard Model and Wizard Pages.
The button panel contains navigation buttons (such as Next and Back) and action buttons (such as Finish and Cancel) that allow the user to control the wizard. For more information on the button panel, see Buttons.
Although an instance of
// create the model that determines the pages WizardModel wizardModel = ... // create the Swing component JWizard wizard = new JWizard( wizardModel ); // show the modal dialog int result = wizard.showDialog( parentFrame, “Wizard Title” );
The value returned from Side PanelYou can place any component in the wizard’s side panel. Simply create the component and invoke
void setAccessory( JComponent accessory ); When sizing the dialog, the layout manager tries to
respect the side panel’s minimum and maximum sizes. If you do not explicitly
set this accessory component or if you set it with
The default value is set using:
void setDefaultAccessory( int defaultAccessory ); By default, the value is
The actual steps displayed in the list are fetched from the wizard model. For more information, see The Wizard Model.
To hide the side panel, you must ensure that the accessory
component and default accessory are set to ButtonsThe buttons in the
When the last page is displayed, a Finish button appears
on the button panel. This button replaces the Last button, if one exists;
otherwise, it replaces the Next button. To change the Finish button’s text,
tool tip, or mnemonic, use the following
void setFinishButtonText( String finishButtonText ); void setFinishButtonToolTipText( String finishButtonToolTipText ); void setFinishButtonMnemonic( int finishButtonMnemonic );
All of the buttons except the Help button depend on the state of the underlying wizard model. The Help button is controlled through the wizard component itself via:
void setHelpButtonIsShown( boolean shown ); In
void setControlButtonsAreShown( boolean shown );
You may want to do this, for instance, to treat a wizard as a browser or as a slide show. Hiding the buttons, however, makes you responsible for advancing the pages. You should invoke the following methods, as needed:
void doCancel(); void doClose(); void doHelp(); void doBack(); boolean doLast(); boolean doNext(); boolean doFinish();
If you wish to know when one of the buttons is pressed,
you can register an action listener with the
sampleWizard.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent event ) { String command = event.getActionCommand(); // respond to the Help button if( JWizard.HELP_ACTION.equals( command )) JOptionPane.showMessageDialog( sampleWizard, "The programmer is responsible for responding to the " + "Help button." ); } } );
The Wizard ModelThe wizard model controls the sequence of pages in the wizard. It has several responsibilities.
First, it keeps track of the current page. You can retrieve the current page with a call to
Page getCurrentPage();
For more information on wizard pages, see Wizard Pages. Second, it controls the stepping through the pages and the execution of the task. The methods that control these are:
void stepNext(); void stepBack(); void stepLast(); void finish(); void cancel();
Not all actions are available at all times. The following methods state whether an action is available.
boolean canStepNext(); boolean canStepBack(); boolean canStepLast(); boolean canFinish(); boolean canCancel();
Some models may not be able to support jumping to the last
page in the sequence. In this case, they return
Third, the wizard model maintains a state. If the wizard model is gathering user input, then its state is WIZARD_IN_PROGRESS. If it is in the middle of executing its task, the state is WIZARD_FINISHING. When the task completes, the model moves into a state of WIZARD_FINISHED. If at any point the model is aborted, its state becomes WIZARD_CANCELED.
Last, the wizard model keeps track of the steps. The steps
are listed in the component’s side panel, depending on the component’s
settings. Steps and pages are entirely unconnected in the
public void addListDataListener(ListDataListener listener); public Object getElementAt(int index); public Object getSelectedItem(); public int getSize(); public void removeListDataListener(ListDataListener listener);
The Wizard Library provides one concrete implementation of
this interface:
The use of The Finish TaskWhen the user hits the wizard’s Finish button, the
wizard’s task executes.
Since wizard tasks are application specific, the Wizard
Library does not provide a complete implementation of
The following is a sample task that does nothing but sleep 100 times (your task will perform something a bit more useful):
Task task = new AbstractTask( "Finishing wizard..." ) { public void run() { for( int i = 1; i <= 100; i++ ) { if( shouldAbort() ) break; try { Thread.currentThread().sleep( 30 ); } catch( InterruptedException ie ) { // ensure thread’s interrupted flag remains set Thread.currentThread().interrupt(); } setProgress( i ); } } // override to indicate that this task is interruptible public boolean isInterruptible() { return true; } }; A Static ModelIf the entire sequence of pages is known at the time the wizard appears, we call this a static, or unconditional, model. The next page to display never depends on the user’s input in a previous page. The easiest way to create a static wizard model is to create the pages and task upfront and invoke the following constructor:
DefaultWizardModel( Page[] pages, Task finishTask, Page summaryPage );
This constructor will automatically create a step for each
page and designate
A Dynamic ModelIf the page sequence depends on the user’s input, we say
that the model is dynamic, or conditional. In actuality,
void addLast( Page page, Transition transition ); void push( Page page, Transition transition );
The
void stepNext(); void stepBack();
In the first method, you will typically add pages, update the last page, and update the finish task as appropriate. In the second method, you will typically remove the pages that you added in the first method.
The following example illustrates the use of a transition. The transition uses the selection of a radio button to determine the subsequent pages.
final DefaultWizardModel model = new DefaultWizardModel(); final JRadioButton option1RadioButton = new JRadioButton( "Show pages 2-4", true ); final Page page4 = ... DefaultWizardModel.Transition selectionPageTransition = new DefaultWizardModel.TransitionAdapter() { public void stepNext() { if( option1RadioButton.isSelected() ) { Page page2 = ... Page page3 = ... model.push( page2 ); model.addLast( page3 ); model.addLast( page4 ); } else { Page page2a = ... model.push( page2a ); model.addLast( page4 ); } } public void stepBack() { int numDynamicPages = option1RadioButton.isSelected()? 3 : 2; for( int i = 0; i < numDynamicPages; i++ ) model.removeLast(); } }; model.addLast( selectionPage, selectionPageTransition ); model.setLastPage( page4 ); Wizard PagesWe have discussed the wizard component and the wizard
model, but we have not addressed the wizard page. Each wizard page must
implement the
Although it is the developer’s responsibility to populate
the wizard model with pages relevant to the task, the library provides two
concrete implementations of this interface:
A page is part of the model (in the Model-View-Controller
architecture), so it is not responsible for its own rendering and it does not
have to implement
The method The OptionPage Page
The appearance of an
The following example demonstrates the creation of an
final JTextField titleTextField = new JTextField( "My First Wizard" ); Object[] titleMessage = new Object[] { "<html>Provide a title for your wizard.<p><html>", titleTextField, "<html><p><p>Each page can specify when it is incomplete " + "or invalid. This page is not complete if the above text field " + "is empty. Note that the <b>Next</b> and <b>Last</b> buttons " + "become disabled if the page is incomplete. This page is invalid " + "if the supplied text contains a non-alphanumeric character. Try " + "typing \"Wizard?\" and clicking <b>Next</b>.</html>" }; final OptionPage titlePage = new OptionPage( "Wizard Title", titleMessage );
The editor renders it as:
By default, an
final OptionPage titlePage = new OptionPage( "Wizard Title", titleMessage ) { public void validate() throws InvalidPageException { String title = titleTextField.getText(); for( int i = 0; i < title.length(); i++ ) { char ch = title.charAt( i ); if( !Character.isLetterOrDigit( ch ) && !Character.isWhitespace( ch )) { titleTextField.requestFocus(); throw new InvalidPageException( "The title may only contain letters and digits." ); } } } }; The ProgressPage Page
If the wizard task is interruptible, the page displays as follows (depending on the names of the page and task):
In most cases, you will not need to concern yourself with
this page. You simply must decide if your task is long enough to warrant a
progress bar and invoke Custom PagesYou may find it worthwhile to create your own type of
page. If you create an implementation of
void setDefaultPageEditor( Class pageClass, PageEditor pageEditor );
Customizing a WizardYou can further customize your wizard by defining look-and-feel properties. At application start-up, define the properties you wish to change with the call
UIManager.put( propertyKey, propertyValue );
where
ExampleWe put most of the ideas discussed above into a complete
example, called
You can run this sample application on the library’s homepage.
Home | Contact Us | Privacy Policy
Copyright © 2016 Side of Software, a branch of Natavision. All rights reserved.
|