使用注册表管理 Swing 操作

发布于 2024-08-03 15:27:00 字数 202 浏览 0 评论 0原文

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

谢谢,

杰夫

Typically when I'm creating a Swing (or any UI) application, I have various Actions that appear on menu items and buttons. I usually create an action registry and store the actions in there and then when certain things occur, I disable/enable actions in the registry based on the state of the application.
I wouldn't call myself an avid Swing developer, although I know my way around it well enough, but is this a pretty typical pattern for managing Actions? Or is there a more standard way of doing it?

thanks,

Jeff

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

猫弦 2024-08-10 15:27:00

杰夫,你的方法似乎是个好方法。我也做同样的事情。我调用注册表 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);

Jeff, your approach seems like a good approach. I do the same thing. I call the registry ActionHandler and it looks like this:

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

Now to disable, say ZoomAction, I use

   ActionHandler.getActionFor(ZoomAction.class).setEnabled(false);
沐歌 2024-08-10 15:27:00

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

您描述的 Action 框架是一个功能强大的工具,允许在许多输入方法之间共享操作(即让工具栏按钮和菜单项执行相同的操作,因此共享相同的 Object 用于处理两者触发的事件等)。这种抽象非常酷,但 Sun 警告说,它比简单的观察者更重一些。来自 Action JavaDoc:< /a>

请注意,Action 实现在存储方面往往比典型的 ActionListener 更昂贵,后者不提供功能集中控制和属性更改广播的优点。因此,您应该注意仅在需要其好处的地方使用 Action,而在其他地方使用简单的 ActionListener。

From my experience, the 'most' standard way of handling actions performed on a Swing GUI is to create ActionListeners and have them handle ActionEvents directly for the components with which they are registered. It is a simple design and it follows convention with other sorts of GUI events in the Swing framework (MouseListener/MouseEvent, TableModelListener/TableModelEvent, etc).

The Action framework you describe is a powerful tool to allow for sharing of actions between many input methods (ie, having a toolbar button and menu item perform the same action, and therefore sharing the same Object for handling the events triggered by both, etc.). This abstraction is pretty cool, but Sun cautions that it is a bit heavier-weighted than the simple Observers. From the Action JavaDoc:

Note that Action implementations tend to be more expensive in terms of storage than a typical ActionListener, which does not offer the benefits of centralized control of functionality and broadcast of property changes. For this reason, you should take care to only use Actions where their benefits are desired, and use simple ActionListeners elsewhere.

神经暖 2024-08-10 15:27:00

我通常采用以下方法:

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

示例:

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));

顺便说一句,与 ActionListener 相比,我通常更喜欢 Action 来公开构成我的 Component 一部分的 Action的 API。对于仅存在于Component 中的操作(例如对话框的“清除”按钮),我通常使用ActionListener。然而,我不同意 akf 认为 ActionListener 是最标准方法的观点 - 这对于较小的 GUI 可能是正确的,但对于更复杂的 Swing 应用程序则不然。

I usually take the following approach:

  • Register the Action with the containing Component's action map.
  • Define a public String constant allowing the application bootstrap code to "pull out" the Action from the Component in required (e.g. to add it to a JToolBar, JMenuBar, etc.).
  • Define a private updateActionStates() method within the Component, which is called when the user performs some action (e.g. selects N rows from a JTable). This method enables / disables all bespoke actions based on the current state of the Component.

Example:

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));

Incidentally, I typically prefer Actions to ActionListeners for exposing Actions that form part of my Component's API. For Actions that merely exist within the Component (e.g. a dialog's "Clear" button) I typically use ActionListener. However, I disagree with akf about ActionListener being the most standard approach - This may be true of smaller GUIs but not more complex Swing applications.

巷雨优美回忆 2024-08-10 15:27:00

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

更整洁一些,并且新操作会自动管理。

I'm using annotations on actions, then finding them reflectively.

A bit tidier, and new actions get managed automatically.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文