Java FX Kontrollelemente
Willemers Informatik-Ecke

Label

Ein Label zeigt einen Text an. Es dient der Beschriftung von Dialogen, aber auch, um Ergebnisse anzuzeigen. Der Label an sich ist passiv. Es fängt keine Ereignisse, sondern ist einfach nur schön.

import javafx.scene.control.Label;
// ...
Label beschriftung = new Label("Erhellender Text");
Auch wenn er karg daher kommt, so sind doch fast alle Kontrollelemente seine Kinder und erben darum auch seine Methoden: Das folgende Beispiel führt dazu, dass durch Eingabe von [Alt]+[G] das Eingabefeld für die Größe den Fokus erhält, auch wenn er zuvor in einem anderen Eingabefeld war.
labGroesse = new Label("_Größe (cm):");
labGroesse.setMnemonicParsing(true);
...
txtGroesse = new TextField();
labGroesse.setLabelFor(txtGroesse);

Button

Buttons nehmen einen Klick entgegen und führen fast immer zu Aktionen. Darum wird ihnen über die Methode setOnAction ein Eventhandler zugewiesen.

Ihre Beschriftung erhalten Buttons entweder durch ihren Konstruktorparameter oder durch die Methode setText.

Button button = new Button();
button.setText("Drück mich!");
button.setOnAction(new EventHandler<ActionEvent>() {
     @Override
     public void handle(ActionEvent event) {
         System.out.println("Hab' Dich auch lieb!");
     }
});

TextField

Ein Eingabefeld, damit der Anwender auch mal einen Namen, eine Zahl oder eine sonstige Textzeile eingeben kann.

In den meisten Fällen müssen diese Felder nur beim Start eines Dialogs gesetzt und beim Beenden wieder ausgelesen werden. Dazu dienen die Methoden getText() und setText().

TextField eingabe = new TextField();
eingabe.setText("Vorgabeeingabe");
String str = eingabe.getText();
Auch das TextField kennt Ereignisse, die den Programmierer interessieren. Darunter fällt der Fokuswechsel. Ein Kontrollelement hat den Fokus, wenn die Tastatur auf das Element gelenkt ist. Besonders spannend ist bei einem TextField der Fokusverlust, weil in diesem Augenblick geprüft werden kann, ob die Eingabe korrekt ist.
TextField eingabe = new TextField();
eingabe.focusedProperty().addListener(new InvalidationListener() {
    @Override
    public void invalidated(Observable observable) {
        if (eingabe.isFocused()) {
            System.out.println("Fokus bekommen");
        } else {
            System.out.println("Fokus verloren");
        }
    }
});
Soll die fehlerhafte Eingabe beim Eintippen verhindert werden, erzeugen Sie eine eigene Klasse, die TextField erweitert und überschreiben die Methode replace. Die folgende Klasse lässt nur numerische Eingaben zu. Sie ersetzt für numerische Eingaben die Klasse TextField.
class NumTextField extends TextField {
    @Override
    public void replaceText(int start, int end, String text) {
        if (text.isEmpty() || "0123456789.,-".contains(text)) {
            super.replaceText(start, end, text);
        }
    }
}

CheckBox und ToggleButton

Diese beiden Abarten des Buttons dienen dazu den logischen Status durch einen Haken (CheckBox) oder durch Tiefe (ToggleButton) darzustellen und zu erfassen.
CheckBox check = new CheckBox("Check");
ToggleButton toggle = new ToggleButton("Toggle");

RadioButton

Ein RadioButton entspricht in seiner Funktion einem ToggleButton. Seine Besonderheit ist, dass er in einer ToggleGroup organisiert ist. Von allen zu einer ToggleGroup organisierten RadioButtons kann nur einer aktiviert sein.

Ein RadioButton wird über seine Methode setToggleGroup der Gruppe zugewiesen, die als Parameter übergeben wird.

ToggleGroup senderGroup = new ToggleGroup();
RadioButton radioArd = new RadioButton("ARD");
radioArd.setToggleGroup(senderGroup);

ChoiceBox oder ComboBox

Bei ChoiceBox und ComboBox handelt es sich um Klapplisten, aus deren Elementen der Anwender eines auswählen kann. Zur Füllung der Klappliste wird eine ObservableList eingesetzt.
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ChoiceBox;
// ...
ChoiceBox<String> wahl = new ChoiceBox<String>();
ObservableList<String> list = FXCollections.observableArrayList
                ("ARD", "ZDF", "N3");
wahl.setItems(list);
wahl.addEventHandler(ActionEvent.ACTION, new EventHandler() {
    @Override
    public void handle(ActionEvent event) {
        System.out.println(wahl.getValue()); // selektiertes Element;
    }
});

Beispiel BMI-Rechner

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class FxBmiAlter extends Application {
    Label labMeldung = null;
    Label labBmi = null;
    TextField txtGroesse = null;
    TextField txtGewicht = null;
    ComboBox<String> wahlalter = null;

    @Override
    public void start(Stage hauptStage) {
        Label labGroesse, labGewicht;
        Button btnStart;
        // der Hauptcontainer bekommt ein Borderlayout
        BorderPane border = new BorderPane();
        // hinein wird ein kleiner JPanel gesetzt
        GridPane innen = new GridPane();
        border.setCenter(innen);
        // innen.setLayout(new GridLayout(5, 2));
        // erzeuge die Kontrollelemente
        // Radio fuer M/W
        ToggleGroup grpGeschlecht = new ToggleGroup();
        RadioButton radioMaennlich = new RadioButton("männlich");
        RadioButton radioWeiblich = new RadioButton("weiblich");
        radioMaennlich.setToggleGroup(grpGeschlecht);
        radioWeiblich.setToggleGroup(grpGeschlecht);
        radioMaennlich.setSelected(true);
        // Die Labels
        labGroesse = new Label("Größe (cm):");
        labGewicht = new Label("Gewicht (kg):");
        Label labAlter = new Label("Alter:");
        labMeldung = new Label(" ");

        labBmi = new Label(" ");
        // Die Eingabefelder
        txtGroesse = new TextField();
        txtGewicht = new TextField();
        // Die Combobox für das Alter
        ObservableList<String> strAlterWahl = FXCollections.observableArrayList( "unter 25", "bis 34", "bis 44", "bis 54", "bis 64", "über 65");
        ComboBox wahlAlter = new ComboBox<String>(strAlterWahl);
        wahlAlter.setItems(strAlterWahl);
        // Der Startbutton
        btnStart = new Button("OK");
        int zeile = 0;
        // Zusammenbau aller Elemente
        innen.add(new Label("Geschlecht:"), 0, zeile);
        innen.add(radioMaennlich, 1, zeile++);
        innen.add(radioWeiblich, 1, zeile++);
        innen.add(labGroesse, 0, zeile);
        innen.add(txtGroesse,1, zeile++);
        innen.add(labGewicht, 0, zeile);
        innen.add(txtGewicht, 1, zeile++);
        innen.add(labAlter, 0, zeile);
        innen.add(wahlAlter, 1, zeile++);
        innen.add(labBmi, 0, zeile);
        innen.add(btnStart, 1, zeile++);
        // So kann die Meldung über die gesamte Breite gehen
        border.setBottom(labMeldung);
        // zusammenpacken und darstellen

        // Bereite die Reaktion auf den Button-Klick vor
        btnStart.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                if (txtGroesse.getText().length() > 0 && txtGewicht.getText().length() > 0) {
                    try {
                        int groesse = Integer.parseInt(txtGroesse.getText());
                        int gewicht = Integer.parseInt(txtGewicht.getText());
                        double bmi = gewicht / (groesse * groesse / 10000.0);
                        // Eine Nachkommastelle reicht beim BMI
                        bmi = Math.round(bmi * 10.0) / 10.0;
                        labBmi.setText("BMI = " + bmi);
                        // korrigiere BMI bei Frauen
                        if (radioWeiblich.isSelected()) {
                            bmi++;
                        }
                        // Alterszuschlag
                        int alter = wahlAlter.getSelectionModel().getSelectedIndex();
                        if (alter > 0)
                            bmi -= alter;
                        if (bmi < 20.0) {
                            labMeldung.setText("Untergewicht");
                        } else if (bmi <= 25.0) {
                            labMeldung.setText("Normalgewicht");
                        } else if (bmi <= 30) {
                            labMeldung.setText("Übergewicht");
                        } else if (bmi <= 40) {
                            labMeldung.setText("Adipositas");
                        } else {
                            labMeldung.setText("Starke Adipositas");
                        }
                    } catch (NumberFormatException ex) {
                        labMeldung.setText("Fehlerhafte Eingabe");
                    }
                } else {
                    labMeldung.setText("Fehlende Eingaben");
                }
            }
        });
        Scene scene = new Scene(border, 400, 300);
        hauptStage.setScene(scene);
        hauptStage.show();
    }

    public static void main(String[] args) {
        launch(args); // sorgt indirekt für den Aufruf von start
    }
}

ListView

Die ListView wird wie ComboBox und ChoiceBox mit einer ObservableList gefüllt. Sie nimmt naturgemäß mehr Raum ein und dient nicht in erster Linie der Auswahl sondern der Darstellung von Daten.

ListViews können auch mehrere Spalten darstellen.

TableView

Der TableView entspricht einer ListView, verfügt aber darüber hinaus auch noch Spaltenüberschriften. Für weitere Informationen folgen Sie dem Link.

Menüs

import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
...
MenuBar menuBar = new MenuBar();
Menu menuFile = new Menu("File");
Menu menuEdit = new Menu("Edit");
Menu menuView = new Menu("View");
menuBar.getMenus().addAll(menuFile, menuEdit, menuView);
Das Menü muss noch in das Fenster eingebaut werden. Der Rahmen des Fensters ist meist sinnvollerweise ein BorderPane, in dessen Top-Bereich ein Menü geradezu ideal hineinpasst.
root.setTop(menuBar);
Nun haben wir eine Menüleiste, es fehlen aber die Menüpunkte, die man unter FX MenuItem nennt. Sie müssen erzeugt werden und in das passende Menu mit der Methode addAll() eingehängt werden.
MenuItem mnOpen = new MenuItem("Öffnen");
MenuItem mnSave = new MenuItem("Speichern");
MenuItem mnEnde = new MenuItem("Ende");
mnDatei.getItems().addAll(mnOpen, mnSave, mnEnde);
Zu guter Letzt soll natürlich auch irgendetwas passieren, wenn der Benutzer auf die Menüpunkte klickt, sonst hätte man sich den ganzen Zirkus ja auch sparen können. In dieser Hinsicht verhalten sich Menüpunkte wie Buttons und binden mit der Methode setOnAction() einen Eventhandler an ihre Aktion.
mnEnde.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        System.exit(0);
    }
});

Beispiel für Menüs mit Standarddialogen

Das folgende Beispiel zeigt ein Programm mit einem Menü, über das Standarddialoge von FX aufgerufen werden. Zu den Standarddialogen gehören die Dateiauswahlboxen, Nachrichtendialoge und einfache Eingabeboxen.
import java.io.File;
import java.util.Optional;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputDialog;
import javafx.scene.layout.BorderPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

public class FxMenueDialoge extends Application 
                implements EventHandler<ActionEvent> {
    public static void main(String[] args) {
        launch(args);
    }

    MenuItem mnOpen = new MenuItem("Öffnen");
    MenuItem mnSave = new MenuItem("Speichern");
    MenuItem mnDir = new MenuItem("Verzeichnis");
    MenuItem mnEnde = new MenuItem("Ende");
    MenuItem mnNote = new MenuItem("Meldung");
    MenuItem mnInput = new MenuItem("Eingabe");
    MenuItem mnJaNein = new MenuItem("Ja/Nein");
    Stage stage = null;

    @Override
    public void start(Stage primaryStage) throws Exception {
        stage = primaryStage;
        MenuBar menuBar = new MenuBar();
        Menu menuDatei = new Menu("Datei");
        Menu menuEdit = new Menu("Bearbeiten");
        Menu menuView = new Menu("Ansicht");
        menuBar.getMenus().addAll(menuDatei, menuEdit, menuView);
        BorderPane borderpane = new BorderPane();
        borderpane.setTop(menuBar);
        menuDatei.getItems().addAll(mnOpen, mnSave, mnDir, mnEnde);
        mnOpen.setOnAction(this);
        mnSave.setOnAction(this);
        mnDir.setOnAction(this);
        mnEnde.setOnAction(this);
        menuView.getItems().addAll(mnNote, mnInput, mnJaNein);
        mnJaNein.setOnAction(this);
        mnNote.setOnAction(this);
        mnInput.setOnAction(this);
        Scene scene = new Scene(borderpane, 400, 300);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void handle(ActionEvent event) {
        if (event.getSource() == mnEnde) {
            System.exit(0);
        } else if (event.getSource() == mnOpen) {
            FileChooser fileChooser = new FileChooser();
            File file = fileChooser.showOpenDialog(stage);
            if (file != null) {
                System.out.println(file.getPath());
            }
        } else if (event.getSource() == mnSave) {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Speichern der Datei");
            File file = fileChooser.showSaveDialog(stage);
            if (file != null) {
                System.out.println(file.getPath());
            }
        } else if (event.getSource() == mnDir) {
            DirectoryChooser dirChooser = new DirectoryChooser();
            File selDir = dirChooser.showDialog(stage);
            if (selDir != null) {
                System.out.println(selDir.getPath());
            }
        } else if (event.getSource() == mnNote) {
            Alert alert = new Alert(AlertType.INFORMATION);
            alert.setTitle("Titelzeile");
            alert.setHeaderText("Dies ist eine Information!");
            alert.setContentText("Ich habe da etwas zum Drücken!");
            alert.showAndWait().ifPresent(rs -> {
                if (rs == ButtonType.OK) {
                    System.out.println("Pressed OK.");
                }
            });
        } else if (event.getSource() == mnInput) {
            TextInputDialog dialog = new TextInputDialog("Vorgabe");
            dialog.setTitle("Eingabedialog");
            dialog.setHeaderText("Bitte eingeben!");
            dialog.setContentText("Wie heißen Sie?");
            Optional<String> result = dialog.showAndWait();
            if (result.isPresent()) {
                System.out.println("Dein Name: " + result.get());
            }
        } else if (event.getSource() == mnJaNein) {
            Alert alert = new Alert(AlertType.CONFIRMATION);
            alert.setTitle("Bestätigung");
            alert.setHeaderText("Freidefinierte Buttons");
            alert.setContentText("War das klug?");
            ButtonType btJa = new ButtonType("Ja");
            ButtonType btNein = new ButtonType("Nein");
            ButtonType btEgal = new ButtonType("Egal");
            ButtonType btAbbruch = new ButtonType("Abbrechen", ButtonData.CANCEL_CLOSE);
            alert.getButtonTypes().setAll(btJa, btNein, btEgal, btAbbruch);
            Optional<ButtonType> result = alert.showAndWait();
            if (result.get() == btJa) {
                System.out.print("Ja");
            } else if (result.get() == btNein) {
                System.out.print("Nein");
            } else if (result.get() == btEgal) {
                System.out.print("Egal");
            } else {
                System.out.print("Weg hier!");
            }
            System.out.println(result.get().getText());
        }
    }
}