6

我编写了一个 Swing GUI,其中包含与同一Action子类关联的多个控件。子类的实现Action遵循这个伪代码:

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_;
};

该操作与按钮和菜单项相关联,其方式类似于以下伪代码:

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

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

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

这引发了两个问题:

  1. 像我在这里所做@Override的那样对我来说可以吗?isEnabled()
  2. 假设 #1 的答案是肯定的,我如何触发 GUI 的刷新以便isEnabled()再次调用,从而导致按钮和菜单项被禁用?
4

4 回答 4

3

在您的方法中初始化您的小工具之后,setEnabled您可以简单地调用,而不是覆盖:setEnabled(false)actionPerformed

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

这是setEnabled来自的实现AbstractAction

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

您正在寻找的自动firePropertyChange是对 的调用,它根据此操作通知组件状态已更改,因此组件可以相应地更新自己的状态。

于 2012-07-09T16:18:19.653 回答
2

我不是这方面的专业人士,但我看不到这样做的自动方式,即通知听众启用状态已更改。当然,您可以setEnabled(false)在 actionPerformed 开始时调用,然后对 Gizmo(或 Gizmo 上的包装器)进行编码以支持属性更改,然后将 PropertyChangeListener 添加到 Gizmo,并在该侦听器中,当状态更改为 DONE 时,调用setEnabled(true). 有点笨拙,但它会起作用。

于 2012-07-09T16:19:10.807 回答
2

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

如果您有动态行为,则应在每次值更改时调用相应的 setter。这将通知已经进行了超类更改,并且通常这还会触发属性更改事件以通知其他相关方。

如果您对 Java bean 进行搜索,您可以找到更多关于此约定的信息。

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

于 2012-07-09T16:28:43.980 回答
0

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

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

  1. 在菜单的按钮中。
  2. 在工具栏中。
  3. 在示例中的快捷方式Strgp中。

它们都可以具有相同的Action_startPlayback. Action_startPlayback是唯一的真相来源。组件有责任尊重这一事实来源,因此每个组件都会要求 AbstractAction 通知它们是否有更改。AbstractAction 将记住所有组件并使用 Method 通知它们firePropertyChange()

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

@Override public void actionPerformed(ActionEvent e) 
{
  gizmo_ = new Gizmo();
  // now, force the components to get notified.
  setEnabled(true);
}
于 2015-12-12T09:19:37.137 回答