自动更新Action的isEnabled()

时间:2012-07-09 15:59:13

标签: java swing

我编写了一个Swing GUI,其中有几个控件与同一个Action子类相关联。 Action子类的实现遵循此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_;
};

该操作与按钮和菜单项相关联,方式与此psudocode类似:

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

当我点击按钮或菜单项时,操作actionPerformed被正确触发,gizmo_被初始化并且不是null,一切都按预期工作 - 除了按钮和菜单项仍然启用。

我预计isEnabled会被“自动”再次调用,但这显然不会发生。永远不会再调用isEnabled()

这引出了两个问题:

  1. 我可以像@Override isEnabled()方法那样使用isEnabled()方法吗?
  2. 假设#1的答案是肯定的,我如何触发GUI的刷新,以便再次调用{{1}},从而产生按钮&菜单项被禁用?

4 个答案:

答案 0 :(得分:2)

您可以在setEnabled方法中对Gizmo进行初始化后,轻松调用setEnabled(false),而不是覆盖actionPerformed

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

以下是setEnabled的{​​{1}}实施:

AbstractAction

您要查找的自动是对public void setEnabled(boolean newValue) { boolean oldValue = this.enabled; if (oldValue != newValue) { this.enabled = newValue; firePropertyChange("enabled", Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } } 的调用,它会根据此操作通知组件状态已更改,因此组件可以更新其自己的状态相应

答案 1 :(得分:2)

我不是这方面的专业人士,但我没有看到自动执行此操作的方法,通知听众已启用状态已更改。当然你可以在actionPerformed开始时调用setEnabled(false),然后编译Gizmo(或Gizmo上的包装器)以获得属性更改支持,然后将PropertyChangeListener添加到Gizmo,并在该侦听器中,当状态发生更改时要完成,请致电setEnabled(true)。有点kludgy但它会工作。

答案 2 :(得分:2)

这并不仅限于Swing,而是更普遍的Java原则。 JDK(以及其他库)中的许多类都有一个getter和一个属性的setter。这些方法并不意味着被覆盖以返回动态值,因为大多数时候超类直接访问相应的字段而不会通过getter。

如果您有动态行为,则每次值更改时都应调用相应的setter。这将通知超级类已经做出的更改,通常这也会触发属性更改事件以通知其他感兴趣的各方。

如果您搜索Java bean,可以在此约定上找到更多信息。

在您的情况下,可能的解决方案是让您的UI类在PropertyChangeEvent实例更改时触发gizmo,并让您的操作侦听该事件。当他们收到这样的事件时,他们会更新自己的启用状态。

答案 3 :(得分:0)

启用状态存储在对象的 ,AbstractAction和JButton中。

这很重要,因为您只需要一个Action_StartPlayback个实例用于多个组件,例如:

  1. 在菜单的按钮中。
  2. 在工具栏中。
  3. 在示例中的快捷方式 Strg p 中。
  4. 所有这些都可以拥有Action_startPlayback的相同实例。 Action_startPlayback唯一的真相来源。组件负责尊重真实来源,因此每个组件都会要求AbstractAction在事情发生变化时通知他们。 AbstractAction将记住所有组件,并将使用方法firePropertyChange()通知它们。

    但是如何重新绘制所有待处理的组件?您必须强制所有待处理的组件向Action_startPlayback询问执行启用状态!看看这个:

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