JavaFX mit selbst entwickelter Hardware ergänzen

Wie schon erwähnt, können wir dieses Programm nur auf dem Raspberry Pi ausprobieren. Da dies so simpel und nicht besonders beeindruckend ist, machen wir uns direkt an den JavaFX-Code.

Anders als mit Swing besteht in JavaFX die Möglichkeit, das GUI über XML zu definieren und mittels CSS zu stylen. Davon machen wir nun gleich Gebrauch, indem wir die Datei Gui.css im main/resource-Verzeichnis erstellen. Die Ressourcendateien sollten sich im gleichen Unterverzeichnis oder Package befinden wie anschließend der JavaFX-Code, allerdings im Ressourcenverzeichnis und nicht im Source-Verzeichnis.

Listing 5
#Background {
  -fx-background-color: #18171d;
}
.Off {
  -fx-background-color: #18171d;
  -fx-background-image: url('panic_off.png');
  -fx-background-size: stretch;
}
.On {
  -fx-background-color: #18171d;
  -fx-background-image: url('panic_on.png');
  -fx-background-size: stretch;
}

Die Klassen .On und .Off in Listing 5 spiegeln den Status des Tasters wider. Wir ändern einfach das Hintergrundbild bei einem Statuswechsel. Die beiden Bilder werden im gleichen Verzeichnis wie Gui.css platziert. Das GUI selbst wird wie in Listing 6 in der Datei Gui.fxml definiert.

Listing 6

          

In der GUI-Definition wird ein Button der Größe 400 x 400 Pixel in der Mitte des Bildschirms platziert. Als Startwert setzen wir die CSS-Klasse Off. Durch unsere Style-Klasse wird der Button nur als Bild und nicht als klassischer Button erscheinen. Mit onMousePressed und onMouseReleased registrieren wir noch zwei Events, damit wir die Statusänderung auch über die Maus auslösen können. Die beiden Events referenzieren Methoden in einem Controller, den wir gleich implementieren werden. Zum Schluss wird unter stylesheets unsere CSS-Definition bekanntgemacht.

Jetzt muss noch das Model mit dem JavaFX-Button verknüpft werden. Dies geschieht in einer Controller-Klasse, die in Listing 7 zu sehen ist. Im GuiController registrieren wir in der Initialisierungsmethode einen Listener, der die CSS-Klasse des Buttons entsprechend dem Modellzustand setzt. Durch die Annotation @FXML füllt uns JavaFX bereits die Referenz zum Button ab. Dabei muss die Member-Variable gleich heißen wie die fx:id in Gui.fxml.

Listing 7
public class GuiController implements Initializable {
  private BooleanProperty model;
  @FXML
  private Button button;
  public GuiController(BooleanProperty model) {
    this.model = model;
  }
  @Override
  public void initialize(URL url, ResourceBundle resourceBundle) {
  model.addListener(new OnOffCssChangeListener(button));
  }
  public void onMousePressed(MouseEvent event) {
    model.set(true);
  }
  public void onMouseReleased(MouseEvent event) {
    model.set(false);
  }
} 

Am Ende der Klasse finden wir ebenfalls die beiden Event-Methoden, die wir in Gui.fxml definiert haben. Der erwähnte Listener für die CSS-Updates gestaltet sich auch sehr einfach und lässt sich, wie Listing 8 zeigt, in wenigen Zeilen implementieren.

Listing 8
public class OnOffCssChangeListener implements ChangeListener {
  private static final String ON_CLASS = "On";
  private static final String OFF_CLASS = "Off";
  private Node node;
  public OnOffCssChangeListener(Node node) {
    this.node = node;
  }
  @Override
  public void changed(final ObservableValue extends Boolean> observable, final Boolean oldValue, final Boolean newValue) {
    Platform.runLater(new Runnable() {
      @Override
      public void run() {
      ObservableList styleClass = node.getStyleClass();
        styleClass.remove(ON_CLASS);
        styleClass.remove(OFF_CLASS);
        styleClass.add(newValue ? ON_CLASS : OFF_CLASS);
      }
    });
  }
}

In der changed-Methode modifizieren wir einfach die Liste mit Style-Klassen unseres Buttons. Dabei ist zu beachten, dass die Änderungen im JavaFX Application Thread durchgeführt werden. Dies wird durch runLater in der Platform-Klasse sichergestellt. Beim ersten Wechsel wird unser Raspberry Pi etwas Zeit benötigen, um unser Bild zu laden. Würde dies nicht im Application Thread vorsichgehen, so könnte ein sehr kurzer Klick auf unseren Hardware-Taster unser GUI durcheinander bringen, da sich die On- und Off-Events überholen könnten. Solche Effekte werden erst auf dem langsameren Endgerät richtig gut sichtbar.

Unser GUI ist somit fertig und testbereit. Das GUI ohne Hardware kann über das Programm in Listing 9 auf dem Entwicklungsrechner gestartet werden.

Listing 9
public class GuiOnlyApp extends Application {
  @Override
  public void start(Stage stage) throws Exception {
    BooleanProperty model = new SimpleBooleanProperty();
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Gui.fxml"));
    fxmlLoader.setController(new GuiController(model));
    Parent root = (Parent) fxmlLoader.load();
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.setFullScreen(true);
  stage.show();
  }
  public static void main(String[] args) {
    launch(args);
  }
}
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.