Automatic update of isEnabled () action

I wrote a Swing GUI with several controls related to the same Action subclass. The implementation of the Action subclass follows this psudocode:

 public class MyGUI { Gizmo gizmo_; // Defined elsewhere public class Action_StartPlayback extends AbstractAction { /* ctor */ public Action_StartPlayback(String text, ImageIcon icon, String desc, Integer mnem) { super(text, icon); putValue(SHORT_DESCRIPTION, desc); putValue(MNEMONIC_KEY, mnem); } @Override public boolean isEnabled() { return gizmo_ == null; } @Override public void actionPerformed(ActionEvent e) { gizmo_ = new Gizmo(); } Action_StartPlayback act_; }; 

The action is associated with both the button and the menu item, similar to this psudocode:

 act_ = new Action_StartPlayback(/*...*/); // ... JButton btn = new JButton(act_); JMenu mnu = new JMenu(act_); 

When I click a button or menu item, the actionPerformed action starts correctly, gizmo_ initialized and not null , and everything works as expected, except that the button and menu item are still on.

I was expecting isEnabled to be called โ€œautomaticallyโ€ again, but this obviously does not happen. isEnabled() is never called again.

This raises two questions:

  • How @Override fit the isEnabled() method, how did I do it?
  • Assuming the answer to # 1 is yes, how can I call a GUI update to call isEnabled() again, causing the button and menu item to be disabled?
+6
source share
4 answers

Instead of overriding setEnabled , you can simply call setEnabled(false) after you initialize your gizmo in the actionPerformed method:

 @Override public void actionPerformed(ActionEvent e) { gizmo_ = new Gizmo(); setEnabled(false); } 

Here's the implementation of setEnabled from AbstractAction :

 public void setEnabled(boolean newValue) { boolean oldValue = this.enabled; if (oldValue != newValue) { this.enabled = newValue; firePropertyChange("enabled", Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } } 

The automatic search you are looking for is a call to firePropertyChange , which notifies the components based on this action that the state has changed, so the component can accordingly update its own state.

+2
source

I'm not a professional at this, but I donโ€™t see an automatic way to do this, notifying listeners that the state of inclusion has changed. Of course, you can call setEnabled(false) at the beginning of the actionPerformed and then the Gizmo code (or the wrapper on Gizmo) to have support for changing properties, and then add the PropertyChangeListener to Gizmo and in this listener, when the state changes to DONE, call setEnabled(true) . A bit kludgy, but it will work.

+2
source

This is not strictly limited to Swing, but to the more general principle of Java. Many classes in the JDK (and other libraries) have getter and setter for the property. These methods are not intended to be overridden to return a dynamic value as most of the time when the superclass accesses the corresponding field directly and does not go through the getters.

If you have dynamic behavior, you must call the appropriate installer every time you change the value. This will notify changes to the superclass, and usually it will also result in a property change event to notify other interested parties.

You can find a little more about this convention if you do a search in Java beans.

In your case, a possible solution is to allow your user interface class to run PropertyChangeEvent when this gizmo instance changes and let your actions listen for this event. When they receive such an event, they update their enabled state.

+2
source

The included state is stored in both your objects, in AbstractAction and in JButton.

This is important because you only need one instance of Action_StartPlayback for multiple Components, such as:

  • In the menu button.
  • On the toolbar.
  • In the shortcut Strg p in the example.

All of them can have the same instance of Action_StartPlayback . Action_StartPlayback is the only source of truth . Components are responsible for observing this source of truth , so each component will ask AbstractAction to notify them if something has been changed. AbstractAction will remember all components and notify them using the firePropertyChange() method.

But how to redraw all pending components? You must force all pending components to request Action_StartPlayback for the activated activation state! Look at this:

 @Override public void actionPerformed(ActionEvent e) { gizmo_ = new Gizmo(); // now, force the components to get notified. setEnabled(true); } 
0
source

Source: https://habr.com/ru/post/920047/


All Articles