Best approach for dual-state Action
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
.
- 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 aJMenuBar
as well as aJButton
, so do not think this is appropriate).
EDIT
Specifically, how do applications like IDEA deal with this? Would they us开发者_开发问答e multi-state actions (as above) or would they swap a different Action
into a given JButton
using setAction(Action)
? Perhaps this approach is better?
- When updating an action's properties
can I rely on GUI components
initialised with that
Action
(e.g.JButton
) automatically repainting themselves? What if theJButton
size changes as a result? Should I be revalidating the containingJPanel
myself? - 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.
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.
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
精彩评论