使用注册表管理Swing操作

时间:2009-08-24 23:49:20

标签: java swing user-interface action

通常,当我创建Swing(或任何UI)应用程序时,我会在菜单项和按钮上显示各种操作。我通常创建一个动作注册表并将动作存储在那里,然后当某些事情发生时,我根据应用程序的状态禁用/启用注册表中的动作。 我不会称自己是一个狂热的Swing开发人员,虽然我知道我的方法很好,但这是一个非常典型的管理动作的模式吗?或者有更标准的方法吗?

感谢,

杰夫

4 个答案:

答案 0 :(得分:10)

杰夫,你的方法似乎是一种很好的方法。我做同样的事情。我调用注册表ActionHandler,它看起来像这样:

import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;

import javax.swing.*;
import javax.swing.text.DefaultEditorKit;

public class ActionHandler {

    private static final ClassToInstanceMap<Action> actionMap =
            new ImmutableClassToInstanceMap.Builder<Action>().
                    put(DefaultEditorKit.CutAction.class, new DefaultEditorKit.CutAction()).
                    put(DefaultEditorKit.CopyAction.class, new DefaultEditorKit.CopyAction()).
                    put(DefaultEditorKit.PasteAction.class, new DefaultEditorKit.PasteAction()).
                    put(RefreshAction.class, new RefreshAction()).
                    put(MinimizeAction.class, new MinimizeAction()).
                    put(ZoomAction.class, new ZoomAction()).
                    build();

    public static Action getActionFor(Class<? extends Action> actionClasss) {
        return actionMap.getInstance(actionClasss);
    }
}

现在禁用,比如说ZoomAction,我用

   ActionHandler.getActionFor(ZoomAction.class).setEnabled(false);

答案 1 :(得分:5)

根据我的经验,处理在Swing GUI上执行的操作的' most '标准方法是创建ActionListener并让他们直接处理ActionEvent s他们注册的组件。它是一个简单的设计,它遵循Swing框架中的其他种类GUI事件(MouseListener / MouseEventTableModelListener / TableModelEvent等)。

您描述的Action框架是一个强大的工具,允许在许多输入方法之间共享操作(即,使工具栏按钮和菜单项执行相同的操作,因此共享相同的{{1}用于处理由两者触发的事件等)。这种抽象很酷,但是Sun警告说它比简单的Observers重一点。来自Action JavaDoc:

  

请注意,就典型的ActionListener而言,Action实现在存储方面往往更昂贵,而ActionListener不提供集中控制功能和广播属性更改的好处。出于这个原因,您应该注意只使用需要其好处的Actions,并在其他地方使用简单的ActionListener。

答案 2 :(得分:5)

我通常采用以下方法:

  • Action注册到包含Component的操作地图。
  • 定义一个公共String常量,允许应用程序引导代码从所需的Action“拉出”Component(例如将其添加到JToolBarJMenuBar等。)。
  • updateActionStates()中定义私有Component方法,该方法在用户执行某些操作时调用(例如,从JTable中选择N行)。此方法根据Component的当前状态启用/禁用所有定制操作。

示例:

public class MyPanel extends JPanel {
  public static final String MY_ACTION_NAME = "MyAction";

  private final JTable myTable;       

  public MyPanel() {
    // Create action and define behaviour.
    this.myAction = new AbstractAction(MY_ACTION_NAME, ...);

    // Register with component's action map.
    getActionMap().put(myAction.getValue(Action.NAME), myAction);

    // Optionally register keyboard shortcuts using component's input map.
    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(...);

    // Create JTable and add a call to updateActionStates when the selection changes.
    myTable = new JTable(...);
    myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent evt) {
        updateActionStates();
      }
    });
  }

  private void updateActionStates() {
    // Action will only be enabled if one table row is selected.
    getActionMap.get(MY_ACTION_NAME).setEnabled(myTable.getSelectedRowCount == 1);
  }
}

// Application start-up code:

MyPanel pnl = new MyPanel();
JToolBar toolBar = new JToolBar();
// Pull out action from action map and add to toolbar.
toolBar.add(pnl.getActionMap().get(MyPanel.MY_ACTION_NAME));

顺便说一句,我通常更喜欢ActionActionListener来展示构成Action API一部分的Component。对于仅存在于Component内的动作(例如对话框的“清除”按钮),我通常使用ActionListener。但是,我不同意akf关于ActionListener是最标准的方法 - 这可能适用于较小的GUI但不是更复杂的Swing应用程序。

答案 3 :(得分:0)

我在动作上使用注释,然后反思地找到它们。

有点整洁,新动作会自动管理。