Question

I have recently implemented an Action that toggles the enabled status of a business function. Whenever the user invokes the action I set a boolean flag: "willEnable" to determine whether the next invocation will enable or disable the function. Likewise I update the action name, short description and icon to reflect the new state. Then within my actionPerformed(...) method I take a different action based on the state of willEnable.

  1. Is this the correct approach or can anyone recommend a better one (as I suspect this is a common problem)? (I can see that JToggleButton acts as a two-state button but I want this Action to be visible on a JMenuBar as well as a JButton, so do not think this is appropriate).

EDIT

Specifically, how do applications like IDEA deal with this? Would they use multi-state actions (as above) or would they swap a different Action into a given JButton using setAction(Action)? Perhaps this approach is better?

  1. When updating an action's properties can I rely on GUI components initialised with that Action (e.g. JButton) automatically repainting themselves? What if the JButton size changes as a result? Should I be revalidating the containing JPanel myself?
  2. Is changing the action's name a bad thing to do? This is the only way I can make the JButton text change, but am concious that the name should probably remain constant if the action is being placed in an ActionMap.

Thanks in advance.

Was it helpful?

Solution

I would expect that any GUI component which is created with some data "model" (I would include an Action as a data model) should register itself as a listener to that model. It must take appropriate, erm, action on a PropertyChangeEvent being fired: any other behaviour would constitute a bug in my opinion.

The questionable thing here is whether it is legitimate to change the name of the action; I think that it is not legitimate. Your action logically is ToggleEnabledStatus and that does not change because the action has been invoked. Any component which needs to display any other text should register itself as a listener to the Action and then check your willEnable flag to take the appropriate, erm, action.

Alternately you could write your own class which implemented ToggleButtonModel and Action at the same time and controlled the change events from within it. This is a lot of code, however, for such little benefit

OTHER TIPS

You may want to look at the State Pattern.

Basically, you create an interface and two (or more) implementations of it for each state. As a simple example, the disable state might just implement the interface to do nothing while the enabled state does some actions. To switch state you would simply do

interface IState {
  void doAction();
  boolean isEnabled();
}

class EnabledState implement IState {
  void doAction() {
    setState(new DisabledState());
    // do something
  }
  boolean isEnabled() {return true;}
}

class DisabledState implement IState {
  void doAction() {
    setState(new EnabledState());
    // do nothing
  }
  boolean isEnabled() {return false;}
}

private IState state = new DisabledState(); // default is disabled
private PropertyChangeSupport support = new PropertyChangeSupport(this);

void setState(IState state) {
  if (this.state != state) {
    IState oldState = this.state;
    this.state = state;
    support.firePropertyChange("enabled", oldState.isEnabled(), state.isEnabled());
  }
}

void doAction() {
  state.doAction();
}

While it is a little overhead for a single method, it certainly pays of as soon as you have several methods that change it's behavior depending on a single state.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top