Управление действиями Swing с помощью реестра - PullRequest
8 голосов
/ 25 августа 2009

Обычно, когда я создаю приложение Swing (или любой пользовательский интерфейс), у меня есть различные действия, которые появляются в пунктах меню и кнопках. Обычно я создаю реестр действий и сохраняю действия там и тогда, когда происходят определенные вещи, я отключаю / включаю действия в реестре в зависимости от состояния приложения. Я бы не назвал себя заядлым разработчиком Swing, хотя я достаточно хорошо разбираюсь в этом, но достаточно ли это типичный шаблон для управления действиями? Или есть более стандартный способ сделать это?

спасибо,

Jeff

Ответы [ 4 ]

10 голосов
/ 25 августа 2009

Джефф, твой подход кажется хорошим подходом. Я делаю то же самое. Я называю реестр 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);
5 голосов
/ 25 августа 2009

Я обычно придерживаюсь следующего подхода:

  • Зарегистрируйте Action с помощью карты действий Component.
  • Определите общедоступную константу String, позволяющую коду начальной загрузки приложения "вытянуть" Action из необходимого Component (например, добавить его к JToolBar, JMenuBar и т. Д.).
  • Определить закрытый updateActionStates() метод внутри Component, который вызывается, когда пользователь выполняет какое-либо действие (например, выбирает N строк из JTable). Этот метод включает / отключает все сделанные на заказ действия в зависимости от текущего состояния Component.
* * Пример тысяча двадцать-один: * * 1 022
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));

Кстати, я обычно предпочитаю Action с ActionListener с для показа Action с, которые являются частью моего Component API. Для действий, которые просто существуют внутри Component (например, кнопка «Очистить» диалогового окна), я обычно использую ActionListener. Тем не менее, я не согласен с тем, что ActionListener является наиболее стандартным подходом - это может быть справедливо для небольших графических интерфейсов, но не для более сложных приложений Swing.

5 голосов
/ 25 августа 2009

Исходя из моего опыта, ' most ' стандартным способом обработки действий, выполняемых в графическом интерфейсе Swing, является создание ActionListener s и их обработка ActionEvent s непосредственно для компонентов, с которыми они работают. зарегистрировано. Это простой дизайн, который следует соглашению с другими видами событий GUI в среде Swing (MouseListener / MouseEvent, TableModelListener / TableModelEvent и т. Д.).

Каркас Action, который вы описываете, является мощным инструментом, позволяющим разделять действия между многими методами ввода (т. Е. Чтобы кнопка на панели инструментов и пункт меню выполняли одно и то же действие и, следовательно, совместно использовали один и тот же Object для обработки события, вызванные обоими и т. д.). Эта абстракция довольно крутая, но Sun предупреждает, что она немного тяжелее, чем простые наблюдатели. Из Action JavaDoc:

Обратите внимание, что реализации Action, как правило, обходятся дороже с точки зрения хранения, чем обычный ActionListener, который не предлагает преимуществ централизованного управления функциональностью и трансляции изменений свойств. По этой причине вам следует позаботиться о том, чтобы использовать Действия только там, где их преимущества желательны, и использовать простые ActionListeners в других местах.

0 голосов
/ 07 марта 2011

Я использую аннотации к действиям, затем нахожу их рефлексивно.

Немного опрятнее, и новые действия управляются автоматически.

...