JavaFX Dialog - Auswahl des ausgewählten Buttons mit Enter


Ein Bestätigungsdialog mit JavaFX ist schnell gezaubert. Wenn man dann aber zwischen den Buttons mit den Pfeiltasten hin- und her navigieren möchte und mit der ENTER-Taste den selektierten Button wählen möchte, stößt man auf Probleme. Zunächst einmal ist ein Button standardmäßig als Default-Button gekennzeichnet. Das heißt, wenn die ENTER-Taste gedrückt wird, dann wird auch dieser Button gewählt. Ganz egal, auf welchem Button der Fokus liegt.
Der kleine Code-Schnipsel zeigt, wie ein Bestätigungsdialog gebaut wird, wo sich der jeweils ausgewählte Button mit der ENTER-Taste betätigen läßt. Das Beispiel ist natürlich auf alle Dialoge anwendbar.

Alert alert = new Alert(AlertType.CONFIRMATION);
alert.getButtonTypes().clear();
alert.getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
Ein neuer Alert-Dialog wird gebaut vom Typ CONFIRMATION. Auf diesem befinden sich die Buttons Ok und Cancel. Da wir aber lieber Yes und No auf den Buttons lesen würden, löschen wir die Buttons und setzen neue.

Button yesButton = (Button) alert.getDialogPane().lookupButton(ButtonType.YES);
yesButton.setDefaultButton(false);
Der erste Button auf dem Dialog ist automatisch als Default-Button gesetzt. Also jener, der bei Betätigung der ENTER-Taste immer ausgewählt wird. Da dies nicht mehr gewünscht ist, wird der erste Button, also hier der Yes-Button über ein LookUp auf dem DialogPane geholt und als Default-Button deaktiviert.

Jetzt fehlt nur noch, dass die ENTER-Taste jeden ausgewählten Button feuert. Dafür bekommt jeder Button ein Event-Handler, der bei der ENTER-Taste den Button feuert.

EventHandler fireOnEnter = event -> {
   if (KeyCode.ENTER.equals(event.getCode()) && event.getTarget() instanceof Button) {
      ((Button) event.getTarget()).fire();
   }
};
Der EventHandler schaut, ob es sich um die ENTER-Taste handelt und einem Button-Event. Ist dies so, wird der Button gefeuert.

DialogPane dialogPane = alert.getDialogPane();
dialogPane.getButtonTypes().stream().map(dialogPane::lookupButton).forEach(button -> button.addEventHandler(KeyEvent.KEY_PRESSED, fireOnEnter));
Und hier wird für jeden Button ein Event-Handler gesetzt. Nach Java 8 Manier durchlaufen wir alle Buttons des DialogPane und fügen den EventHandler hinzu.

Optional result = alert.showAndWait();
if (result.get() == ButtonType.YES) {
   alert.close();
}
Anzeige des Dialogs und Verarbeitung des Dialog-Ergebnisses erfolgt wie gewohnt.
Tags: java fx, dialog, focus, enter
Guido Oelmann     Sonntag, 3. Juli 2016 1    1339
@
(Email Adresse wird nicht veröffentlicht)
(kein HTML erlaubt)
Bitte beantworten Sie die einfache mathematische Frage.
  


René Bühling 06.10.2017 14:54
Sehr cool, besten Dank!
Beim EventHandler musste ich in meinem Fall noch den Ereignis-Typ angeben:
EventHandler{KeyEvent} fireOnEnter = event -> ...
sonst kennt er getCode() usw nicht. ({ und } durch Kleiner/Größer-Zeichen ersetzen, ist hier im Kommentar scheinbar nicht erlaubt)