Java 自动更新操作';s isEnabled()

Java 自动更新操作';s isEnabled(),java,swing,Java,Swing,我已经编写了一个Swing GUI,其中有几个控件与相同的操作子类关联。操作子类的实现遵循以下psudocode: public class MyGUI { Gizmo gizmo_; // Defined elsewhere public class Action_StartPlayback extends AbstractAction { /* ctor */ public Action_StartPlayback(String text, ImageIc

我已经编写了一个Swing GUI,其中有几个控件与相同的
操作
子类关联。
操作
子类的实现遵循以下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_;
};
act_ = new Action_StartPlayback(/*...*/);
// ...
JButton btn = new JButton(act_);
JMenu mnu = new JMenu(act_);
该操作与按钮和菜单项相关联,方式类似于此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_;
};
act_ = new Action_StartPlayback(/*...*/);
// ...
JButton btn = new JButton(act_);
JMenu mnu = new JMenu(act_);
当我单击按钮或菜单项时,操作的
actionPerformed
被正确触发,
gizmo\uuz
被初始化且为非
null
,并且一切都按预期工作——除了按钮和菜单项仍处于启用状态

我原以为
isEnabled
会被再次“自动”调用,但这显然没有发生<代码>isEnabled()将不再被调用

这引发了两个问题:

  • 像我在这里所做的那样,
    @重写
    isEnabled()
    方法可以吗
  • 假设#1的答案是“是”,如何触发GUI刷新,以便再次调用
    isEnabled()
    ,从而禁用按钮和菜单项

  • actionPerformed
    方法中初始化gizmo后,您可以简单地调用
    setEnabled(false)
    ,而不是覆盖
    setEnabled

    @Override public void actionPerformed(ActionEvent e) 
    {
      gizmo_ = new Gizmo();
      setEnabled(false);
    }
    
    下面是
    AbstractAction
    中的
    setEnabled
    实现:

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

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

    我对此不在行,但我看不到一种自动执行此操作的方法,通知侦听器enabled的状态已更改。当然,您可以在开始执行操作时调用
    setEnabled(false)
    ,然后对Gizmo(或Gizmo上的包装器)进行编码以获得属性更改支持,然后将PropertyChangeListener添加到Gizmo,在该侦听器中,当状态更改为“完成”时,调用
    setEnabled(true)
    。有点笨拙,但它会工作。

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

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

    如果您在JavaBean上进行搜索,您可以找到更多关于此约定的信息


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

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

    这一点很重要,因为对于以下多个组件,您只需要一个
    Action\u StartPlayback
    实例:

  • 在菜单的按钮中
  • 在工具栏中
  • 在示例中的快捷方式Strgp中
  • 它们都可以具有相同的
    操作\u startPlayback
    实例。
    行动\u startPlayback
    是真相的唯一来源。组件有责任尊重这个真相来源,因此每个组件都会要求AbstractAction通知他们是否发生了更改。AbstractAction将记住所有组件,并使用方法
    firePropertyChange()
    通知它们

    但如何重新绘制所有挂起的组件?您必须强制所有挂起的组件向
    操作\u startPlayback
    询问实际启用状态!看看这个:

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

    我可能会建议发布一个更好的帮助sooner@DavidKroukamp当前位置我能做到,尽管这需要一些时间。有了使用其他GUI框架(如MFC)的经验,我原以为这将是大多数Java GUI程序员面临的一项相当基本的任务。也许不是这样。那是AbstractAction的代码吗?如果是这样,为什么不允许“enabled”作为有效的属性名?没有固定的Action字段或AbstractAction可以说明这一点。我最初的方法是从
    actionPerformed()
    中调用
    setEnabled()
    ,这很有效。然而,在我的实际用例中,我有几个控件,它们的启用状态与某个中心参考变量相关联(在本例中,
    gizmo
    )。我试图将业务逻辑(实际上是
    actionPerformed()
    所做的)与GUI更新逻辑(设置/清除各种启用状态)分开。如果是真的,这让我成为一个可悲的程序员。这种混乱正是我试图避免的,因为我最终会有十几个控件和一系列不同的操作。维护所有这一切是动作本身负责更新其他动作的已启用状态将从维护的角度变得相当麻烦。@ GrunCH:我认为Gizmo是GUI的“模型”的一部分,当然,向模型中添加监听器并由于这些监听器被触发而更改视图状态也不少见。它的级别比你习惯的要低一点,但它很能干,也不太笨拙。+1:所以基本上你是说我没有用“Java方式”来做这件事,这就是它不起作用的原因。我担心情况可能是这样。我将关注触发一个
    propertychangevent,
    ,这是我以前从未听说过的事情。(我是C++的家伙,只做了几天的java)@格伦奇。我不知道你还能怎么实现这个。不发射任何事件基本上是f