X

Geertjan's Blog

  • April 6, 2008

Disabling/Enabling a Wizard Panel's Finish Button

Geertjan Wielenga
Product Manager
Let's take the wizard panel from a few days ago and disable the "Finish" button until both the new fields are filled in:


  1. Change the visual panel's signature so that it implements DocumentListener. Then, in the constructor, add a DocumentListener to both of your new fields:

    extField.getDocument().addDocumentListener(this);
    impField.getDocument().addDocumentListener(this);

    Next, implement the DocumentListener's methods like this:

    @Override
    public void changedUpdate(DocumentEvent e) {
    panel.fireChangeEvent();
    updateUI(e);
    }
    @Override
    public void insertUpdate(DocumentEvent e) {
    panel.fireChangeEvent();
    updateUI(e);
    }
    @Override
    public void removeUpdate(DocumentEvent e) {
    panel.fireChangeEvent();
    updateUI(e);
    }
    public void updateUI(DocumentEvent e) {
    if (this.extField.getDocument() == e.getDocument()) {
    firePropertyChange(EXTENSION, null, this.extField.getText());
    }
    if (this.impField.getDocument() == e.getDocument()) {
    firePropertyChange(IMPLEMENTATION, null, this.impField.getText());
    }
    }

  2. In the non-visual wizard panel, add the code that receives the change event and enables/disables the "Finish" button:

    private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(1);
    @Override
    public final void addChangeListener(ChangeListener l) {
    synchronized (listeners) {
    listeners.add(l);
    }
    }
    @Override
    public final void removeChangeListener(ChangeListener l) {
    synchronized (listeners) {
    listeners.remove(l);
    }
    }
    protected final void fireChangeEvent() {
    Set ls;
    synchronized (listeners) {
    ls = new HashSet(listeners);
    }
    ChangeEvent ev = new ChangeEvent(this);
    for (ChangeListener l : ls) {
    l.stateChanged(ev);
    }
    }
    @Override
    public boolean isValid() {
    if (getExtensionFromVisualPanel().length() == 0 ||
    getImplementationFromVisualPanel().length() == 0) {
    return false;
    }
    return true;
    }

  3. Finally, make sure the two classes are correctly hooked up together. In the wizard panel, pass the current class to the visual panel:

    @Override
    public Component getComponent() {
    if (component == null) {
    component = new FancyVisualPanel1(this);
    }
    return component;
    }

    In the visual panel, receive the wizard panel in the constructor:

    private FancyWizardPanel1 panel;
    public FancyVisualPanel1(FancyWizardPanel1 panel) {
    initComponents();
    this.panel = panel;
    extField.getDocument().addDocumentListener(this);
    impField.getDocument().addDocumentListener(this);
    }

That's it. Now, if both fields aren't filled in, the "Finish" button is disabled. You can also display some kind of informative message so that the user knows what they should do to enable the "Finish" button. In real life, you probably don't want to force the user to fill in an extension class and an implementation class, because possibly they want to have a signature that doesn't include superclasses and/or interfaces. So you'd probably add a checkbox that enables/disables the two fields, depending on whether the user wants to fill them in or not.

Join the discussion

Comments ( 5 )
  • Andrei Badea Monday, April 7, 2008

    Simpler than doing your own listener management is to use ChangeSupport in the Utilities API.

    Not entirely clear who listens on the property change events fired by

    firePropertyChange(EXTENSION, null, this.extField.getText());


  • Luis Tuesday, April 8, 2008

    Hi,

    I just want to know how to copy the information that users puts in the first screen of a wizard to the second screen to ask for confirmation.

    I have something like this in the performAction method.

    public void performAction() {

    //Some default declarations for the wizard

    //created by NetBeans templates.

    boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.CANCEL_OPTION;

    boolean finished = wizardDescriptor.getValue() == WizardDescriptor.FINISH_OPTION;

    boolean next = wizardDescriptor.getValue().equals(WizardDescriptor.NEXT_OPTION);

    if (!cancelled) {

    // do something

    }

    if(next){

    //copy the values to ask for confirmation

    NuevaInstalacionWizardPanel1 o = (NuevaInstalacionWizardPanel1) panels[0];

    NuevaInstalacionWizardPanel2 o2 = (NuevaInstalacionWizardPanel2) panels[1];

    String t1 = o.getComponent().getTextField(1).getText();

    String t2 = o.getComponent().getTextField(2).getText();

    String t3 = o.getComponent().getTextField(3).getText();

    String t4 = o.getComponent().getTextField(4).getText();

    String t5 = o.getComponent().getTextField(5).getText();

    o2.getComponent().getLabel(1).setText(t1);

    o2.getComponent().getLabel(2).setText(t2);

    o2.getComponent().getLabel(3).setText(t3);

    o2.getComponent().getLabel(4).setText(t4);

    o2.getComponent().getLabel(5).setText(t5);

    }

    if (finished) {

    //stores in DB. This works fine.

    }

    }

    The "finish" part of the code works fine, and I've already tried the same code for the "Next" button but nothing happens!!

    When I click the "Next" button in the wizard it appears not to enter to the performAction method.

    What can I do? I'm using NetBeans 6.1 Beta

    I created the methods getTextField and getLabel in the dataVisualPanel1 and dataVisualPanel2, and made the proper changes for the other classes so I can have enabled and disabled by events the "next" and "finish" buttons and that works fine too.

    In advance, thanks!!


  • Luis Wednesday, April 9, 2008

    I've already solved the problem, I made it trough the properties, actually the properties refreshes themselves, so you can pass data from one window to another of the wizard.


  • Vlad Saturday, May 31, 2008

    Luis, could you please describe how you did it through properties? I have the same problem...


  • Luis Monday, June 2, 2008

    There are two methods in each WizardPanel:

    public void readSettings(Object settings) {

    }

    public void storeSettings(Object settings) {

    }

    In these two methods you can pass any object.

    here is an example:

    In the first WizardPanel,

    public void storeSettings(Object settings) {

    wizardDescriptor = (WizardDescriptor) settings;

    String t1 = component.getTextField(1).getText();

    wizardDescriptor.putProperty("text1", t1);

    }

    In the second WizardPanel,

    public void readSettings(Object settings) {

    wizardDescriptor = (WizardDescriptor) settings;

    String t1 = (String)wizardDescriptor.getProperty("text1");

    component.getLabel(1).setText(t1);

    }

    I hope this was helpful.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.