3.07 Weitere GUI-Komponenten

Einleitung

Ein paar einfache GUI-Komponten haben wir in dieser Lektion schon kennengelernt. Nun wollen wir uns noch ein paar weitere ansehen, die man sicherlich früher oder später benötigen wird. Allerdings werden wir auch hier nicht auf restlos alle eingehen können, da dies einfach zu umfangreich wäre.

Komponenten zum Treffen von Wahlen

Toogle Group

Erinnern wir uns noch einmal kurz an Toggle Buttons. Dies sind Schaltflächen, die man ein- und ausschalten kann, z.B., um gewisse Funktionen eines Programms zu aktivieren oder zu deaktivieren. Im Beispiel zu den Mouse Events in dieser Lektion haben wir beispielsweise einen Toggle Button verwendet.

Eine JavaFX-Anwendung mit zwei Toggle Button „Hallo“ und „Tschüss“.
Entweder Begrüßen oder Verabschieden – beides gleichzeitig geht nicht!

Wenn wir mehrere solche Buttons verwenden, könnte es sein, dass es möglich sein soll sie alle unabhängig voneinander ein- und auszuschalten. In diesem Fall müssten wir einfach mehrere Toggle Buttons einfügen.
Es könnte aber auch sein, dass es nur möglich sein soll, aus einer Gruppe von Toggle Buttons immer nur maximal einen zu aktivieren. In diesem Fall, müssen wir diese Gruppe von Toggle Buttons zu einer Toggle Group zusammenfassen.

Sehen wir uns dazu ein Beispiel an:

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.FlowPane;

public class KomponenteToggleGroup extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage meineStage) throws Exception {

        // Erstellen der Komponenten und des Layouts
        meineStage.setTitle("Beispiel Toggle Group");

        // Button ist jetzt als final deklariert.
        final Button meinButton = new Button();
        meinButton.setText("Klick mich!");

        // Gruppe erstellen
        final ToggleGroup meineGruppe = new ToggleGroup();

        // Buttons erstellen und hinzufuegen
        final ToggleButton toggleButtonHallo = new ToggleButton("Hallo");
        toggleButtonHallo.setToggleGroup(meineGruppe);
        final ToggleButton toggleButtonWiedersehen = new ToggleButton("Tschüss");
        toggleButtonWiedersehen.setToggleGroup(meineGruppe);
        
        // Button wird vorselektiert
        toggleButtonHallo.setSelected(true);
        
        // Label ersellen
        Label meinLabel = new Label("Bitte wählen...");

        FlowPane root = new FlowPane();
        root.getChildren().add(toggleButtonHallo);
        root.getChildren().add(toggleButtonWiedersehen);
        root.getChildren().add(meinLabel);
        root.getChildren().add(meinButton);

        Scene meineScene = new Scene(root, 120, 200);

        meineStage.setScene(meineScene);
        meineStage.show();

        // Ereignissteuerung
        meinButton.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
            public void handle(ActionEvent myEvent) {
                if(toggleButtonHallo.isSelected()){
                    meinLabel.setText("Hallo zusammen!");
                }else if(toggleButtonWiedersehen.isSelected()){
                    meinLabel.setText("Bis demnächst!");
                }
            }
        });
    }
}

Unsere Toggle Group wird hier mit der Anweisung final ToggleGroup meineGruppe = new ToggleGroup(); erstellt. Anschließend werden zunächst wie gewohnt die Toggle Buttons erstellt. Allerdings werden sie dann mit toggleButtonHallo.setToggleGroup(meineGruppe); bzw. toggleButtonWiedersehen.setToggleGroup(meineGruppe); dieser Gruppe zugeordnet. Dies hat, wie oben beschrieben, den Effekt, dass immer nur einer der beiden aktiviert sein kann. Es können aber auch beide deaktiviert sein.

Dieser Gruppe könnten wir noch weitere Toggle Buttons hinzufügen. Ebenso könnten wir noch eine weitere unabhängige Toggle Group erstellen.

In dieser Anwendung ist bei Start immer der Toggle Button „Hallo“ aktiviert. Das liegt an der Anweisung toggleButtonHallo.setSelected(true);.

Radio Buttons

Anwendung mit zwei Radio Buttons.
Einer der Radio Buttons ist immer aktiviert.

In vielen Anwendungen findet man eher Radio Buttons anstatt Toggle Buttons vor, wenn es darum geht, aus mehreren Optionen eine auszuwählen. Radio Buttons können wir auch zu einer Toggle Group zusammenfassen. Hier ist es allerdings so, dass immer genau einer der Buttons ausgewählt sein muss – man kann also nicht alle gleichzeitig deaktivieren.

Das Vorgehen ist dasselbe wir bei den Toggle Buttons. Wir  erstellen die Radio Buttons und ordnet sie einer Toggle Group zu:

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.FlowPane;

public class KomponenteRadioButton extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage meineStage) throws Exception {

        // Erstellen der Komponenten und des Layouts
        meineStage.setTitle("Beispiel Radio Buttons");

        // Button ist jetzt als final deklariert.
        final Button meinButton = new Button();
        meinButton.setText("Klick mich!");

        // Gruppe erstellen
        final ToggleGroup meineGruppe = new ToggleGroup();

        // Buttons erstellen und hinzufuegen
        final RadioButton radioButtonHallo = new RadioButton("Hallo");
        radioButtonHallo.setToggleGroup(meineGruppe);
        final RadioButton radioButtonWiedersehen = new RadioButton("Auf Wiedersehen");
        radioButtonWiedersehen.setToggleGroup(meineGruppe);
        
        // Button wird vorselektiert
        radioButtonHallo.setSelected(true);
        
        // Label ersellen
        Label meinLabel = new Label("Bitte wählen...");

        FlowPane root = new FlowPane();
        root.getChildren().add(radioButtonHallo);
        root.getChildren().add(radioButtonWiedersehen);
        root.getChildren().add(meinButton);
        root.getChildren().add(meinLabel);

        Scene meineScene = new Scene(root, 200, 100);

        meineStage.setScene(meineScene);
        meineStage.show();

        // Ereignissteuerung
        meinButton.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
            public void handle(ActionEvent myEvent) {
                if(radioButtonHallo.isSelected()){
                    meinLabel.setText("Hallo zusammen!");
                }else if(radioButtonWiedersehen.isSelected()){
                    meinLabel.setText("Bis demnächst!");
                }
            }
        });
    }
}

Auch hier wird explizit angegeben, welcher der Buttons bei Start des Programms aktiviert sein soll. Die Anweisung ist auch hier radioButtonHallo.setSelected(true);. Wie von den Toggle Buttons gewohnt, können wir mit der Methode isSelected() abfragen, ob ein Button aktiviert ist.

Check Boxes

Drei Check Boxes zur Bestellung von extra Zutaten bei einer Pizza.
Check Boxes lassen sich unabhängig voneinander anwählen.

Auf den ersten Blick sehen Check Boxes den Radio Buttons recht ähnlich. Es gibt aber den wichtigen Unterschied, dass Check Boxes immer unabhängig voneinander angewählt werden können. Da dies den Nutzungserfahrungen mit allen erdenklichen Anwendungen entspricht, sollten wir Check Boxes auch immer in dieser Weise verwenden. Sonst würden wir Verwirrung stiften.

Eine Check Box kann drei verschiedene Zustände einnehmen. Einerseits kann sie angewählt oder nicht angewählt sein, anderseits kann ihr Zustand aber auch unbestimmt sein. Ob sie angewählt ist, fragt man mit isSelected() ab, ob ihr Zustand unbestimmt ist mit isIndeterminate().

Im Beispiel sind die Zustände aller drei Check Boxes zunächst unbestimmt. Solange noch nicht alle ein- oder ausgeschaltet wurden, wird man bei Klicken des Buttons aufgefordert, seine Auswahl zu treffen.

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class KomponenteCheckBox extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage meineStage) throws Exception {

        // Erstellen der Komponenten und des Layouts
        meineStage.setTitle("Beispiel Check Boxes");

        // Button ist jetzt als final deklariert.
        final Button meinButton = new Button();
        meinButton.setText("Klick mich!");

        // Boxen erstellen und hinzufuegen
        final CheckBox checkBoxKaese = new CheckBox("extra Käse");
        final CheckBox checkBoxScharf = new CheckBox("extra scharf");
        final CheckBox checkBoxKnoblauch = new CheckBox("extra Knoblauch");

        checkBoxKaese.setIndeterminate(true);
        checkBoxKnoblauch.setIndeterminate(true);
        checkBoxScharf.setIndeterminate(true);

        // Label ersellen
        Label meinLabel = new Label("Bitte wählen...");

        VBox root = new VBox();
        root.getChildren().add(checkBoxKaese);
        root.getChildren().add(checkBoxScharf);
        root.getChildren().add(checkBoxKnoblauch);
        root.getChildren().add(meinLabel);
        root.getChildren().add(meinButton);

        Scene meineScene = new Scene(root, 400, 200);

        meineStage.setScene(meineScene);
        meineStage.show();

        // Ereignissteuerung
        meinButton.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
            public void handle(ActionEvent myEvent) {
                String bestellung = "Ihre Bestellung: ";
                if (checkBoxKaese.isIndeterminate()
                        || checkBoxScharf.isIndeterminate()
                        || checkBoxKnoblauch.isIndeterminate()) {
                    meinLabel.setText("Bitte Auswahl treffen!");
                } else {
                    if (checkBoxKaese.isSelected()) {
                        bestellung = bestellung + " extra Käse,";
                    }
                    if (checkBoxScharf.isSelected()) {
                        bestellung = bestellung + " extra scharf,";
                    }
                    if (checkBoxKnoblauch.isSelected()) {
                        bestellung = bestellung + " extra Knoblauch";
                    }
                    meinLabel.setText(bestellung);
                }
            }
        });
    }
}

Choice Box

Ein Dropdown-Menü
Menü zur Auswahl der Pizza.

Der Name ist etwas trügerisch, denn eine Choice Box sieht recht anders aus als eine Check Box. Ein Choice Box ist ein Dropdown-Menü, aus dem man einen Eintrag auswählen kann.

Die Einträge, die zur Auswahl stehen, werden dabei in einer Instanz der Klasse ObservableList hinterlegt. Eine solche ist vergleichbar mit einer ArrayList.

Im folgenden Beispiel sind in der Liste Strings hinterlegt. Wir können aber auch eine Observable List für Instanzen einer anderen Klasse erstellen. Wir müssten dann lediglich die entsprechende Klasse in den spitzen Klammern angeben.

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class KomponenteChoiceBox extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage meineStage) throws Exception {

        // Erstellen der Komponenten und des Layouts
        meineStage.setTitle("Beispiel Choice Box");

        // Button ist jetzt als final deklariert.
        final Button meinButton = new Button();
        meinButton.setText("Klick mich!");

        // Boxen erstellen und hinzufuegen
        final ChoiceBox<String> meineBox = new ChoiceBox();
        
        ObservableList<String> angebot = FXCollections.observableArrayList();
        angebot.add("Salami");
        angebot.add("Schinken");
        angebot.addAll("Funghi", "Hawaii");
        
        meineBox.setItems(angebot);

        // Label ersellen
        Label meinLabel = new Label("Bitte wählen...");

        VBox root = new VBox();
        root.getChildren().add(meineBox);
        root.getChildren().add(meinLabel);
        root.getChildren().add(meinButton);

        Scene meineScene = new Scene(root, 200, 200);

        meineStage.setScene(meineScene);
        meineStage.show();

        // Ereignissteuerung
        meinButton.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
            public void handle(ActionEvent myEvent) {
                String bestellung = "Ihre Bestellung: ";
                bestellung = bestellung + meineBox.getValue();
                meinLabel.setText(bestellung);
            }
        });
    }
}

Komponenten für Eingaben

Text Field

Einfache Textfelder haben wir bereits hier kennengelernt. Daher sehen wir uns sie hier direkt im Vergleich zu einem weiteren Eingabefeld an.

Password Field

Anwendung mit Text und Password Field.
Zwei Typen von Eingabefeldern

Ein Password Field unterscheidet sich von einem „normalen“ Eingabefeld dadurch, dass der eingegebene Text nicht lesbar ist, sondern stattdessen nur Punkte angezeigt werden.

Im folgenden Beispiel wurde beim Text Field ein Prompt Text hinzugefügt. Ist das Feld leer und nicht im Fokus, dann erscheint in grauer Schrift das Wort „Benutzername“. Auf diese Weise kann man deutlich machen, was genau in einem Text oder Password Field eingegeben werden soll.

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

public class KomponenteEingabefelder extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage meineStage) throws Exception {

        // Erstellen der Komponenten und des Layouts
        meineStage.setTitle("Beispiel Eingabe");

        // Button ist jetzt als final deklariert.
        final Button meinButton = new Button();
        meinButton.setText("Klick mich!");

        // Boxen erstellen und hinzufuegen
        final TextField name = new TextField();
        name.setPromptText("Benutzername");
        final PasswordField passwort = new PasswordField();

        // Label ersellen
        Label meinLabel = new Label("Bitte Ihre Daten eingeben!");

        VBox root = new VBox();
        root.getChildren().addAll(name, passwort, meinButton, meinLabel);

        Scene meineScene = new Scene(root, 200, 200);

        meineStage.setScene(meineScene);
        meineStage.show();

        // Ereignissteuerung
        meinButton.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent myEvent) {
                if (name.getText().equals("admin")
                        && passwort.getText().equals("passwort")) {
                    meinLabel.setText("Sie sind eingeloggt!");
                }else{
                    meinLabel.setText("Nutzerdaten falsch!");
                }
            }
        });
    }
}