Java Wie Variablen einer JavaFX-GUI an andere (aufrufende) Klassen übergeben?

Endless Storm

Commander
Registriert
Dez. 2008
Beiträge
2.154
Hallo zusammen,

ich scheitere gerade an einem (womöglich einfachen) Problem:
Und zwar übe ich gerade mit JavaFX herum, die GUI erstellen via Scene Builder 2.0 funktioniert prima.
Innerhalb der eigenen Logik (GUI, Controller, aufrufende Klasse mit der "@Override - start"-Methode) funktioniert alles super, Eingabe und Ausgabe (in Textfelder bzw. in der Console).
Allerdings bekomme ich es nicht hin, die Variablen, z.B. Texte, welche ich in der GUI eingegeben habe, auch dauerhaft als Variable innerhalb der Klasse zu speichern.
Was mache ich falsch? Im Internet gibt es meist nur Beispiele von händisch programmierten GUIs, welche ich nachprogrammiert habe, ohne Erfolg.

Zum Verständnis gibt es einmal die FXML-Variante sowie eine händisch-programmierte-Version eines "Login"-Progrämmchens. (Die Codes sind geringfügig um ein paar unwichtige, kommentierte Zeilen bzw. die Imports reduziert)


FXML-Klasse: LogInDialog.fxml
Code:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="150.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="stundenverwaltung.LogInDialogController">
   <children>
      <GridPane layoutX="20.0" layoutY="38.0" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="145.0" minWidth="10.0" prefWidth="108.0" />
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="229.0" minWidth="10.0" prefWidth="192.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <Label text="Nutzername:">
               <padding>
                  <Insets left="10.0" />
               </padding>
            </Label>
            <Label text="Passwort:" GridPane.rowIndex="1">
               <padding>
                  <Insets left="10.0" />
               </padding>
            </Label>
            <TextField fx:id="usernameId" promptText="Bitte Nutzername eingeben" GridPane.columnIndex="1">
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin>
            </TextField>
            <PasswordField fx:id="passwordId" onAction="#firePassword" promptText="Bitte Passwort eingeben" GridPane.columnIndex="1" GridPane.rowIndex="1">
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin>
            </PasswordField>
            <Button fx:id="buttonOkId" minWidth="70.0" mnemonicParsing="false" onAction="#fireOk" onMouseClicked="#fireOk" text="OK" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="2">
               <GridPane.margin>
                  <Insets left="10.0" />
               </GridPane.margin>
            </Button>
            <Button fx:id="buttonCancelId" minWidth="70.0" mnemonicParsing="false" onAction="#fireCancel" onMouseClicked="#fireCancel" text="Abbruch" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin>
            </Button>
         </children>
      </GridPane>
   </children>
</AnchorPane>

Controller-Klasse: LogInDialogController
Code:
public class LogInDialogController implements Initializable {
    @FXML
    private TextField usernameId;
    @FXML
    private PasswordField passwordId;
    @FXML
    private Button buttonOkId;
    @FXML
    private Button buttonCancelId;
    private String user, password;
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
        // Frage: Was tut diese Methode??
    }
    public void firePassword() {
        System.out.printf("Enter nach Passwort  %s %s", usernameId.getText(), passwordId.getText());
        close();
    }
    public void fireOk() {
        System.out.printf("Ok-Button:  %s %s", usernameId.getText(), passwordId.getText());
        setUser(getUsernameId().getText());
        setPassword(getPasswordId().getText());
System.out.printf("Ok-Button 2:  %s %s", getUser(), getPassword()); // später ergänzt
close();
    }
    public void fireCancel() {
        System.out.println("Abbruch-Button");
        close();
    }
    public void close() {
        Stage stage = (Stage) buttonCancelId.getScene().getWindow();
        stage.close();
    }
public TextField getUsernameId() {
        return usernameId;
    }
    public PasswordField getPasswordId() {
        return passwordId;
    }
public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

Beispiel-Klasse zum GUI aufrufen: Login
Code:
public class Login extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Login");
        Pane myPane = (Pane)FXMLLoader
                .load(getClass().getResource("LogInDialog.fxml"));
        Scene myScene = new Scene(myPane);
        primaryStage.setScene(myScene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
LogInDialogController dialog = new LogInDialogController();
        System.out.printf("User: %s, Passwort: %s", dialog.getUser(), dialog.getPassword());
    }
}

Was muss ich in oben genannten Klassen wie tun, damit ich Variablen gespeichert bekomme, um sie z.B. in anderen Klassen zu verwenden?


Anderes Beispiel:
Händisch-programmierte GUI-Klasse TestToDelete
Code:
public class TestToDelete extends Stage {

    private String user = "", password = "";

    public TestToDelete() {
        super();
        setTitle("Login");
        initModality(Modality.APPLICATION_MODAL);
        
        Label l1 = new Label("Bitte Nutzername eingeben:");
        Label l2 = new Label("Bitte Passwort eingeben:");
        TextField tf = new TextField();
        PasswordField pf = new PasswordField();
        Button btnOk = new Button("OK");
        Button btnCancel = new Button("Abbruch");
        GridPane pane = new GridPane();
        pane.setAlignment(Pos.CENTER);
        pane.add(l1, 1, 1);
        pane.add(tf, 2, 1);
        pane.add(l2, 1, 2);
        pane.add(pf, 2, 2);
        pane.add(btnOk, 1, 3);
        pane.add(btnCancel, 2, 3);  
        btnOk.setOnAction(e -> {
            user = tf.getText();
            password = pf.getText();
            close();
        });

        btnCancel.setOnAction(e -> {
            close();
        });
        Scene scene = new Scene(pane, 400, 150);
        setScene(scene);
    }
	
    public String getUser() {
        return user;
    }

    public String getPassword() {
        return password;
    }
}

Zugreifende Klasse: TestToDeleteStart
Code:
public class TestToDeleteStart {
    public static void main(String[] args) {
        TestToDelete ttd = new TestToDelete();
        ttd.showAndWait();
        System.out.printf("User: %s, Password: %s", ttd.getUser(), ttd.getPassword());
    }
}


Ich hoffe ihr habt ein paar Ideen, wie ich das umsetzen kann. In einer klassischen Swing-GUI hätte ich keine Probleme, irgendwie scheint es an der Art zu liegen, mit der die GUI gestartet werden muss. In Swing wollte ich die GUI aber nicht mehr programmieren, da die Technik mittlerweile ja veraltet ist :rolleyes:

Vielen Dank vorab
Endless Storm
 
Zuletzt bearbeitet:
Ich hab zwar keine Ahnung von JavaFX aber ich versuchs mal.
Schon mal bei fireOk() ein Breakpoint gesetzt?Springt er an? Ansonsten die unschöne Variante:
Code:
public String getUser() {
        return getUsernameId().getText();
 }

public String getPassword() {
        return getPasswordId().getText();
}

//Edit
Diese GUI Elemente werden übrigens nicht initialisiert. Es fehlt @FXML


Code:
private PasswordField passwordId;
private Button buttonOkId;
private Button buttonCancelId;
 
Zuletzt bearbeitet:
Dafür habe ich die oberste Codezeile eingefügt
Code:
public void fireOk() {
        System.out.printf("Ok-Button:  %s %s", getUsernameId().getText(), getPasswordId().getText());
        setUser(getUsernameId().getText());
        setPassword(getPasswordId().getText());
        close();
    }

Hier zeigt er mir eindeutig in der Console an, dass der OK-Button geklickt wurde. Er funktioniert also... Die Ausgabe innerhalb der Console funktioniert auch einwandfrei, d.h. der User + Passwort werden korrekt geschrieben, nur wird es nicht in der Variablen gespeichert...
 
Du willst es in Zeile 15 in Login ausgeben?

Das kann ja nicht gehen, die Zeile ist durch, bevor du irgendwas klicken kannst.
 
Wie würde man es umsetzen müssen, wenn ich die Variable weiterverarbeiten möchte? Irgendwie mit einem Observer vielleicht? Hat da jemand einen Beispielcode, der mir weiterhilft?


edit
Hab Zeile 27 des Controllers ergänzt, er scheint es doch zu speichern, er kann es in der zweiten Ausgabe auch auslesen. Also muss scheinbar ein Observer oder so her, der mitteilt, dass dieses Fenster geschlossen wird, damit die aufrufende Methode weitermachen kann. Kann mir da jemand weiterhelfen? Wie würde ich in der Klasse "Login" die Consolenausgabe hin bekommen??
 
Zuletzt bearbeitet:
gar nicht, auf sinnvolle Weise.

Lies dich mal ins Thema MVC ein und schau dir eine JavaFX Einführung an. Die Dokumentation von Oracle ist nicht schlecht.
 
Ich arbeite selber relativ viel mit javafx & dem scenebuilder2.0 - ich deklariere sie meist im Controller als static & man kann dann eben einfach drauf zugreifen, gerade bei einem Canvas hilft das
 
Dann machst du es Designtechnisch schlecht, solltest das für dich behalten und nicht jemandem als Tipp geben.
 
Wie jeder über static Variablen schimpfen, ich sage es in der TE kann sich ja aussuchen was er macht.

Bei uns ist es normal das es um die 8 statischen Variablen pro Programme gibt, ansonsten müsste man zum Teil Variablen durch zisch Klassen schleifen.
 
Lacritz schrieb:
Wie jeder über static Variablen schimpfen, ich sage es in der TE kann sich ja aussuchen was er macht.

Das Problem dabei ist, dass ein unbedarfter Leser denken könnte, dass das ein gängiger Lösungsweg ist. Und der TE kann es sich eben nicht aussuchen, weil er (offensichtlich) keine Alternativen kennt.


Lacritz schrieb:
Bei uns ist es normal das es um die 8 statischen Variablen pro Programme gibt, ansonsten müsste man zum Teil Variablen durch zisch Klassen schleifen.

Von Dependency Injection noch nie gehört?
 
Die ganzen Klassen brauchen auch eine @FXML notation sofern sie im FXML Builder auch erstellt worden sind.

private PasswordField passwordId;
private Button buttonOkId;
private Button buttonCancelId;
private String user, password;

Ebenso kannst du dir "implements Initializable" sparen, es ist veraltet.

Und keine deiner Methoden besitzt eine @FXML Notation in deiner Controller Klasse, ich gehe stark davon aus dass irgend eine dieser Methoden im FXML Builder existiert.
 
Lacritz schrieb:
Wie jeder über static Variablen schimpfen, ich sage es in der TE kann sich ja aussuchen was er macht..

Ja, der TE kann gerne machen was er will und du kannst auch gerne machen was du willst. Aber wenn jemand frage, wie man etwas macht, sollte man eine Antwort geben welche vom Design her sinnvoll ist, heisst erweiterbar, testbar, lesbar etc...

Static Variablen sind das nun mal nicht und JavaFX ist extra so aufgebaut worden, dass man ein sauberes MVC durchziehen kann.
 
Zurück
Oben