2009-08-24 5 views
8

Zwykle podczas tworzenia aplikacji Swing (lub dowolnego interfejsu użytkownika) mam różne akcje wyświetlane w elementach menu i przyciskach. Zwykle tworzę rejestr akcji i zapisuję tam akcje, a kiedy pewne rzeczy się zdarzają, wyłączam/włączam akcje w rejestrze na podstawie stanu aplikacji. Nie nazwałbym siebie zagorzałym deweloperem Swing, chociaż dobrze znam ten sposób, ale czy jest to dość typowy wzorzec do zarządzania Akcje? Czy istnieje bardziej standardowy sposób robienia tego?Zarządzanie działaniami Swing przy użyciu rejestru

Dzięki,

Jeff

Odpowiedz

10

Jeff, twoje podejście wydaje się dobrym podejściem. Robię to samo. Wzywam ActionHandler rejestru i wygląda to tak:

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

teraz wyłączyć, powiedzieć ZoomAction używam

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

Z mojego doświadczenia wynika, że ​​„najbardziej” standardowy sposób postępowania z czynności wykonywanych na GUI Swing jest stworzenie ActionListener s i je obsługiwać ActionEvent s bezpośrednio dla komponentów z którymi są zarejestrowani. Jest to prosty projekt i jest zgodny z konwencjami z innymi rodzajami zdarzeń GUI w strukturze Swing (MouseListener/MouseEvent, TableModelListener/TableModelEvent itd.).

Action ramy można opisać to potężne narzędzie, aby umożliwić dzielenie się działań pomiędzy wielu metod wejściowych (czyli posiadające przycisk paska narzędzi i menu poz wykonywania tej samej czynności, a więc w obrębie tego samego Object do obsługi zdarzeń wyzwalanych przez oba itd.). Ta abstrakcja jest całkiem fajna, ale Sun ostrzega, że ​​jest nieco cięższy niż zwykli obserwatorzy. Z Action JavaDoc:

pamiętać, że implementacje działania wydają się być bardziej kosztowne pod względem przechowywania niż typowy ActionListener, który nie oferuje korzyści scentralizowanej kontroli funkcjonalności i transmisji zmian własności. Z tego powodu należy zadbać o to, aby korzystać z akcji tylko tam, gdzie są one pożądane, i używać prostych ActionListenerów w innym miejscu.

+0

To wszystko ma sens, że jest to ogólnie podejście, które podejmuję. Domyślam się, że próbuję znaleźć najlepsze rozwiązania, aby zarządzać działaniami, gdy będę ich potrzebował ... –

5

ja zazwyczaj następujące podejście:

  • Zarejestruj Action z zawierającego działania Component „s mapie.
  • Zdefiniuj publicznego String stałą pozwalającą kod bootstrap aplikacji „wyciągnąć” z Action z Component w wymagany (na przykład, aby dodać go do JToolBar, JMenuBar, itd.).
  • Zdefiniuj prywatną metodę updateActionStates() w obrębie Component, która jest wywoływana, gdy użytkownik wykonuje pewną akcję (na przykład wybiera N wierszy z JTable). Ta metoda włącza/wyłącza wszystkie indywidualne działania w oparciu o bieżący stan Component.

przykład:

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

Nawiasem mówiąc, zazwyczaj wolą Action S do ActionListener S odsłaniając Action S, które tworzą część API moi Component „S. W przypadku działań, które istnieją jedynie w ramach Component (np. Przycisku "Wyczyść" w oknie dialogowym), zazwyczaj używam ActionListener. Jednak nie zgadzam się z akf o ActionListener będąc najbardziej standardowym podejściem - Może to dotyczyć mniejszych GUI, ale nie bardziej złożonych aplikacji Swing.

0

używam adnotacje na działaniach, a następnie ich znalezieniem refleksyjnie.

Trochę uporządkuj, a nowe akcje będą automatycznie zarządzane.