Home > English, Linux & Programming > A Java Wizard Toolkit

A Java Wizard Toolkit

Well, here goes my first post. This is a toolkit I started developing back in 2006. I am sure there are other, better implementations and I did not develop this small project any further, but I think it’s also a good example on how to program in OO (though I am sure there is much room for improvement, any flames appreciated 😉 ). So, here it goes:

Introduction

The Wizard Toolkit is a java framework / toolkit for the easy use and creation of wizards. This toolkit lets you focus on defining and validating input fields while the control flow and data storage is automated by the surrounding toolkit.

Wizards are a useful way to gather information for different purposes. They interact in form of dialogs, allowing step-by-step data input. Wizards can be used to gather information, for creating specific output or for setting preferences.

Tutorial

The following example serves as a step-by-step tutorial demonstrating the possibilities provided by the toolkit and how to implement a custom wizard based on it. It will consist of three parts, which will be found in most wizards:

  • A welcome dialog
  • Some input forms
  • A final dialog for checking / presenting all input

The toolkit provides two classes for implementing a wizard:

  • Wizard: The main class of any wizard, extending JDialog. Manages the control flow and displays the panels provided. After finishing the input process, it contains the data entered.
  • WizardPanel: An extension of JPanel. Every WizardPanel stands for one step in the dialog process. It may contain everything a JPanel can contain, usually text or input fields.

The welcome dialog

The first step in a dialog system should always be a welcoming screen, describing what needs to be done in the next steps. This way the user can get an overview of the data required or the process he is about to start. So we create a first class extending WizardPanel:

Note: All following sources are excerpts from the example files. For copyright issues look in the according java files.

public class Panel1 extends WizardPanel {
  public Panel1() {
    super(“Welcome”);
    add(new JLabel(“Welcome to the Wizard toolkit demonstration!));
  }
}

The title Welcome is set in the constructor. It is used for the header and for the menu. You might add further welcome information or for example add licence information here.

Theoretically one WizardPanel is sufficient to create the Wizard class, but in the next step we will add the skeleton of the other two panels and then create the Wizard.

Starting the Wizard

public class Panel2 extends WizardPanel {
  public Panel2() {
    super("Options");
  }
}
public class Panel3 extends WizardPanel {
  public Panel3() {
    super(“Finish”);
  }
}
public class WizardExample {
  public static void main(String[] args) {
    WizardPanel[] panels = new WizardPanel[] { new Panel1(),
        new Panel2(), new Panel3() };
    Wizard wizard = new Wizard((JFrame) null, “Wizard Example”, panels);
    wizard.setVisible (true);
    System.out.println(wizard.getProperties());
  }
}

The Wizard class needs three arguments: A parent dialog or frame (may be null), a title and an array with WizardPanels to display. The constructor automatically initializes everything needed for the process and starts after being set visible. When the user finished using the wizard, all data may be gathered via getProperties. With the WizardPanels implemented so far, calling the constructor will open the following dialog:

Welcoming Screen of the Wizard

Welcoming Screen of the Wizard

Menu, header and buttons are created and managed by the toolkit. Only the main panel / content panel needs to be implemented. Back and Finish cannot be selected, as there is no previous WizardPanel and this is not the last WizardPanel. The buttons behaviour may be modified. Selecting Next will display the next dialog, which will be further implemented now.

The options dialog

After the first dialog, the data input forms begin. In this tutorial a WizardPanel with some sample input fields will be implemented, including verification and storage of the data entered. At first, some input components will be added in the panel’s constructor:

public class Panel2 extends WizardPanel {
  private JCheckBox box1, box2;
  private JRadioButton rbutton1, rbutton2;
  private JTextField textField;
 
  public Panel2() {
    super("Options");
 
    box1 = new JCheckBox("Some option");
    box2 = new JCheckBox(
        "If this radio button is selected, you cannot select "next"");
    rbutton1 = new JRadioButton("Select me");
    rbutton2 = new JRadioButton(
        "If this button is selected, clicking "next" will open a Dialog Box.");
    textField = new JTextField(30);
 
    rbutton1.setSelected(true);
 
    setLayout(new GridBagLayout());
 
    GridBagConstraints gc = new GridBagConstraints();
    ButtonGroup rbuttons = new ButtonGroup();
 
    rbuttons.add(rbutton1);
    rbuttons.add(rbutton2);
 
    gc.gridx = gc.gridy = 0;
    gc.anchor = GridBagConstraints.NORTHWEST;
    add(new JLabel("Checkbox options:"), gc);
 
    gc.gridy++;
    add(box1, gc);
 
    // Add other Components
    // ...
  }

The toolkit enables the Back-Button as there is a previous dialog. But we do not want the user to go back, as there is only a welcome screen. On the other hand, we want to disable the forward button if box2 is selected (as described in its text). The toolkit’s control over the buttons may be overridden to implement panel-specific behaviour:

  protected boolean backButtonEnabled() {
    return false;
  }
 
  protected boolean nextButtonEnabled() {
    return !box2.isSelected();
  }

The Wizard toolkit must be specifically told when to refresh the buttons. Therefore it is necessary to add an ActionListener to the component and tell it to refresh the buttons upon selection:

public class Panel2 extends WizardPanel implements ActionListener {
  // ...
 
  public Panel2() {
    // ...
 
    // Refresh buttons upon selecting / deselecting this checkbox
    box2.addActionListener(this);
    box2.setActionCommand("box1");
 
    // ...
  }
 
  public void actionPerformed(ActionEvent e) {
    refreshButtons();
  }
}

If the second radio button is selected, a confirmation box will be opened upon clicking Next. This can be done via verification of the data input. To use this method, all data must be made available to the toolkit. Every information that needs to be stored must be added to a Property object. This data is gathered by the toolkit.

  protected Properties getProperties() {
    Properties properties = new Properties();
 
    properties.setProperty("box1", String.valueOf(box1.isSelected()));
    properties.setProperty("box2", String.valueOf(box2.isSelected()));
    properties.setProperty("rbutton1", String
        .valueOf(rbutton1.isSelected()));
    properties.setProperty("rbutton2", String
        .valueOf(rbutton2.isSelected()));
    properties.setProperty("textfield", textField.getText());
 
    return properties;
  }
 
  protected boolean verifyChanges(Properties properties) {
    if (Boolean.parseBoolean(properties.getProperty("rbutton2"))) {
      return JOptionPane
          .showConfirmDialog(
              this,
              "Are you sure you want to continue with radio button 2 selected?",
              "Please confirm", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
    }
 
    return ALLOW;
  }

Every WizardPanel which gathers information must provide the getProperties method to store its data. Every WizardPanel that needs verification must provide the verifyChanges method. This method either returns ALLOW (true) or DENY (false). If DENY is returned, the toolkit will do nothing upon selecting Next or Finish. Note: The properties given as parameter here are not only the properties of this WizardPanel but the properties of all Panels. This way, data can be verified over multiple steps.

Second Dialog of the Wizard

Second Dialog of the Wizard

Confirmation before Advancing to the next Step

Confirmation before Advancing to the next Step

The finish dialog

On the last dialog we want to display all information entered by the user so far. Therefore we cannot use the constructor for initializing the components, as we do not know what the user has entered previously. Even worse, the user may use the back button and change the data. So we need a way to update all components upon displaying the WizardPanel. This is done via setComponents, which is called upon every display of the WizardPanel and is provided all properties so far:

public class Panel3 extends WizardPanel {
  public Panel3() {
    super("Finish");
 
    setLayout(new GridBagLayout());
  }
 
  protected void setComponents(Properties properties) {
    removeAll();
 
    GridBagConstraints gc = new GridBagConstraints();
 
    gc.gridx = gc.gridy = 0;
    add(new JLabel("All required information have been entered."), gc);
 
    gc.gridy++;
    add(new JLabel(" "), gc);
 
    gc.anchor = GridBagConstraints.NORTHWEST;
    gc.gridy++;
    add(new JLabel("Boxes selected:"), gc);
 
    if (Boolean.valueOf(properties.getProperty("box1"))) {
      gc.gridy++;
      add(new JLabel("Checkbox 1"), gc);
    }
 
    if (Boolean.valueOf(properties.getProperty("box2"))) {
      gc.gridy++;
      add(new JLabel("Checkbox 2"), gc);
    }
 
    if (Boolean.valueOf(properties.getProperty("rbutton1"))) {
      gc.gridy++;
      add(new JLabel("Radio button 1"), gc);
    }
 
    if (Boolean.valueOf(properties.getProperty("rbutton2"))) {
      gc.gridy++;
      add(new JLabel("Radio button 2"), gc);
    }
 
    gc.gridy++;
    add(new JLabel(" "), gc);
 
    gc.gridy++;
    add(new JLabel("Text entered: "), gc);
 
    gc.gridy++;
    add(new JLabel(properties.getProperty("textfield")), gc);
  }
}

Final Dialog of the Wizard, showing Summary

Final Dialog of the Wizard, showing Summary

Conclusion

With this step, all implementation for the example is finished, showing all possibilities this framework provides. You may verify data on the fly or after selecting buttons and override the button behaviour. The toolkit lets you specify custom behaviour when necessary and provides standard control flow when applicable, supporting a very easy and structured way to implement Wizards.

Source code (SVN)

Sorry, this outdated information, if you need the source code, download it from the section below.

This software is developed as open source under the general public licence. You may freely use or modify this software in terms specified by the GPL. The source code is accessible via Subversion with the repository lying at:

feanorscurse.dyndns.org/home/svn/toolkit

Please inform me before publishing any code changes.

Download

The current stable version is 0.2. You may download the toolkit as jar-files or access the source. If you are planning to use this toolkit, it would be nice to leave a comment 🙂 .

Wizard Toolkit v0.2

Wizard Toolkit v0.2 with example application

Categories: English, Linux & Programming Tags: ,
  1. No comments yet.
  1. No trackbacks yet.
*