【问题标题】:Automatic Updating of Action's isEnabled()自动更新 Action 的 isEnabled()
【发布时间】:2012-07-09 15:59:13
【问题描述】:

我编写了一个 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. 我可以像我在这里所做的那样使用@OverrideisEnabled() 方法吗?
  2. 假设 #1 的答案是肯定的,我如何触发 GUI 刷新以便再次调用 isEnabled(),从而导致按钮和菜单项被禁用?

【问题讨论】:

  • 我可能会建议尽快发布SSCCE 以获得更好的帮助
  • @DavidKroukamp:我可以做到,但需要一些时间。拥有其他 GUI 框架(如 MFC)的经验,我曾预计这将是大多数 Java GUI 程序员面临的一项相当基本的任务。或许事实并非如此。

标签: java swing


【解决方案1】:

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

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

这是来自AbstractActionsetEnabled 实现:

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

你正在寻找的自动是对firePropertyChange的调用,它会根据这个动作通知组件状态已经改变,因此组件可以相应地更新自己的状态。 p>

【讨论】:

  • 那段代码来自 AbstractAction 吗?如果是这样,为什么他们不允许“启用”成为有效的属性名称?没有 Action 或 AbstractAction 的常量字段表明这是这样的。
  • 我最初的方法是从actionPerformed() 中调用setEnabled(),这很有效。但是,在我的实际用例中,我有几个控件,它们的启用与某个中心引用变量相关联(在此示例中,gizmo_)。我试图将业务逻辑(actionPerformed() 实际执行的操作)与 GUI 更新逻辑(设置/清除各种启用状态)分开。
【解决方案2】:

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

【讨论】:

  • 如果属实,这让我成为一个可悲的程序员。笨拙正是我想要避免的,因为我最终会有十几个控件和一堆不同的动作。维护所有这些是操作本身负责更新其他操作的启用状态,从维护的角度来看会变得相当麻烦。
  • @Grunch:我认为 Gizmo 是您的 GUI 的“模型”的一部分,由于这些侦听器被触发,将侦听器添加到模型并更改视图状态当然并不罕见。它比你习惯的水平略低,但它相当可行,而且不太笨拙。
【解决方案3】:

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

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

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

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

【讨论】:

  • +1:所以基本上你的意思是我没有按照“Java 方式”来做这件事,这就是它不起作用的原因。我担心可能是这种情况。我会考虑解雇PropertyChangeEvent,,这是我以前从未听说过的。 (我是 C++ 人,刚学 Java 几天)
  • @Grunch 确实如此。不知道你将如何实现这一点。不触发任何事件基本上会强制所有代码不断检查是否没有任何变化(例如,触发您的操作的按钮需要不断检查 isEnabled 是否返回不同的内容以更新其启用状态)
【解决方案4】:

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

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

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

它们都可以拥有相同的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);
}

【讨论】:

    猜你喜欢
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    • 2015-12-10
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多