3.12.4. Command Action Snipped

Im folgenden soll die Verwendung von Command Actions noch einmal anhand eines Beispiels verdeutlicht werden. Die folgenden Abbildung zeigen vorab fertige Ergebnis:

Abbildung 32. Command Action Snipped - Screenshot 1

Command Action Snipped - Screenshot 1

In dem Textfeld wurde der Text Hello World durch den Benutzer eingegeben. Dadurch ist der Save Button neben dem Text Feld sowie in der Toolbar aktiviert. Zudem befindet sich die Action auch noch im File Menu (nicht auf dem Screenshot sichtbar).

Nachdem die Save Action ausgelöst wurde, ist das folgende zu sehen:

Abbildung 33. Command Action Snipped - Screenshot 2

Command Action Snipped - Screenshot 2

Ein Dialog erscheint, dass die Aktion ausgeführt wurde. Wird dieser geschlossen und öffnet man das File Menu, sieht man das folgende:

Abbildung 34. Command Action Snipped - Screenshot 3

Command Action Snipped - Screenshot 3

Der Tooltip zu der Save Action im File Menü zeigt den Grund für die Deaktivierung im Tooltip. Die Save Action soll genau dann enabled sein, wenn der Text im Textfeld sich seit dem letzten Speichern geändert hat.

Der folgende Code zeigt die Implementierung (das vollständige Snipped inklusive Imports befindet sich hier):

  1  public final class CommandActionSnipped implements IApplication {
  2  
  3      @Override
  4      public void start(final IApplicationLifecycle lifecycle) {
  5  
  6          //create a root frame
  7          final IFrameBluePrint frameBp = BPF.frame();
  8          frameBp.setSize(new Dimension(400, 300)).setTitle("Command actions");
  9          final IFrame frame = Toolkit.createRootFrame(frameBp, lifecycle);
 10  
 11          //Create the menu bar
 12          final IMenuBarModel menuBar = frame.getMenuBarModel();
 13  
 14          //Use a border layout
 15          frame.setLayout(BorderLayout.builder().gap(0).build());
 16  
 17          //add a toolbar to the top
 18          final IToolBarModel toolBar = frame.add(BPF.toolBar(), BorderLayout.TOP).getModel();
 19  
 20          //add a composite to the center
 21          final IComposite composite = frame.add(BPF.composite().setBorder(), BorderLayout.CENTER);
 22          composite.setLayout(new MigLayoutDescriptor("[grow][]", "[]"));
 23  
 24          //add a input field and save button to the composite
 25          final IInputField<String> inputField = composite.add(BPF.inputFieldString(), "growx");
 26          final IButton saveButton = composite.add(BPF.button());
 27  
 28          //create save action 
 29          final IAction saveAction = createSaveAction(inputField);
 30  
 31          //create a menu and add save action
 32          final MenuModel menu = new MenuModel("File");
 33          menu.addAction(saveAction);
 34  
 35          //add the menu to the menu bar
 36          menuBar.addMenu(menu);
 37  
 38          //add the action to the toolbar
 39          toolBar.addAction(saveAction);
 40  
 41          //bind the action to the save button
 42          saveButton.setAction(saveAction);
 43  
 44          //set the root frame visible
 45          frame.setVisible(true);
 46      }
 47  
 48      private static IAction createSaveAction(final IInputComponent<String> inputComponent) {
 49          final IActionBuilder builder = Action.builder();
 50          builder.setText("Save");
 51          builder.setToolTipText("Saves the text");
 52          builder.setAccelerator(VirtualKey.S, Modifier.CTRL);
 53          builder.setIcon(IconsSmall.DISK);
 54  
 55          //save command implements ICommandExecutor and IEnabledChecker,
 56          //so set them both
 57          final SaveCommand saveCommand = new SaveCommand(inputComponent);
 58          builder.setCommand(saveCommand, saveCommand);
 59  
 60          return builder.build();
 61      }
 62  
 63      private static final class SaveCommand 
 64          extends AbstractEnabledChecker implements ICommandExecutor, IEnabledChecker {
 65  
 66          private final IInputComponent<?> inputComponent;
 67  
 68          private SaveCommand(final IInputComponent<?> inputComponent) {
 69              this.inputComponent = inputComponent;
 70  
 71              inputComponent.addInputListener(new IInputListener() {
 72                  @Override
 73                  public void inputChanged() {
 74                      fireEnabledStateChanged();
 75                  }
 76              });
 77          }
 78  
 79          @Override
 80          public void execute(final IExecutionContext executionContext) throws Exception {
 81              inputComponent.resetModificationState();
 82              fireEnabledStateChanged();
 83              final String message = "'" + inputComponent.getValue() + "' saved!";
 84              MessagePane.showInfo(executionContext, message);
 85          }
 86  
 87          @Override
 88          public IEnabledState getEnabledState() {
 89              if (!inputComponent.hasModifications()) {
 90                  return EnabledState.disabled("No changes to save");
 91              }
 92              else {
 93                  return EnabledState.ENABLED;
 94              }
 95          }
 96  
 97      }
 98  
 99  }

Die Klasse SaveCommand implementiert sowohl die Schnittstelle ICommandExecutor als auch IEnabledChecker. Dies ist im Beispiel einfacher, da sich nach dem Zurücksetzen des Modification State in Zeile 81 auch der EnabledState ändert. In Zeile 82 werden daher die registrierten Listener darüber informiert. Es ist bei diesem Vorgehen zu beachten, dass in Zeile 58 die saveCommand Instanz doppelt angegeben wird, einmal als ICommandExecutor und einmal als IEnabledChecker.

Beide Schnittstellen in einer Klasse zu implementieren ist nicht ungewöhnlich. In manchem Fällen lassen sich aber auch IEnabledChecker für unterschiedliche Actions wiederverwenden, was eine Trennung der Implementierung nahelegt.


Siehe auch PDF Version dieses Dokuments, Jowidgets API Spezifikation