# Applikation mit mehreren Scenes



## MarkusM (18. Dez 2012)

Hallo,

ich bin noch relativ frisch mit JavaFX unterwegs und wollte mal fragen, wie Ihr eine JavaFX-Applikation mit mehreren Scenes in der Praxis lösen würdet.

Folgende Ausgangslage: 
Ich möchte genre eine kleine "Testanwendung" schreiben in der zunächst ein Anmeldedialog (Scene) erscheinen soll. Nach erfolgter Anmeldung wird der Dialog geschlossen und die eigentliche Applikation (andere Scene) wird gestartet. Hört sich einfach an, aber ich stehe echt auf dem Schlauch...

Hier mal der Code:


```
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
	 
	
public class App extends Application {
	
	public static void main(String[] args) {
        launch(args);
	}
	
    @Override
    public void start(Stage stage) {
        Parent root;
		try {
			root = FXMLLoader.load(getClass().getResource("LoginDialog.fxml"));
			stage.setTitle("User Login");
	    	stage.setScene(new Scene(root));
	    	stage.show();
	        
		} catch (IOException e) {
			e.printStackTrace();
		}
     }
}
```


```
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;

public class FXMLController implements Initializable{

	@FXML private TextField textfieldUsername;
	@FXML private PasswordField passwordfieldPassword;
	@FXML  protected void buttonLogin(ActionEvent event){
		System.out.println("Login | Username: "+ textfieldUsername.getText()+" | Password: "+ passwordfieldPassword.getText()); //  + passwordfieldPassword.getText()
		// Scene schliessen und Application starten.... HIER HÄNGE ICH FEST!!!

	}
	@Override
	public void initialize(URL arg0, ResourceBundle arg1) {
		// TODO Auto-generated method stub
	}
}
```

LoginDialog.fxml
[XML]
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="153.0" prefWidth="217.0" xmlns:fx="http://javafx.com/fxml" fx:controller="com.userlogin.FXMLController">
  <children>
    <GridPane layoutX="7.0" layoutY="15.0">
      <children>
        <TextField fx:id="textfieldUsername" prefWidth="200.0" promptText="Username" GridPane.columnIndex="1" GridPane.rowIndex="1" />
        <PasswordField id="passwordfirldPassword" fx:id="passwordfieldPassword" prefWidth="200.0" promptText="Password" GridPane.columnIndex="1" GridPane.rowIndex="2" />
        <Label id="textfieldUsername" text="Username:" GridPane.columnIndex="0" GridPane.rowIndex="1" />
        <Label text="Password:" GridPane.columnIndex="0" GridPane.rowIndex="2" />
        <Label alignment="TOP_LEFT" contentDisplay="TOP" prefWidth="200.0" text="User Login" GridPane.columnIndex="0" GridPane.columnSpan="2147483647" GridPane.rowIndex="0">
          <font>
            <Font name="System Bold" size="20.0" />
          </font>
        </Label>
      </children>
      <columnConstraints>
        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.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>
    </GridPane>
    <HBox alignment="CENTER_RIGHT" layoutY="105.0" prefHeight="41.0" prefWidth="207.0">
      <children>
        <Button fx:id="buttonLogin" alignment="CENTER_RIGHT" contentDisplay="CENTER" mnemonicParsing="false" onAction="#buttonLogin" prefHeight="21.999908447265625" text="Login" />
      </children>
      <padding>
        <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
      </padding>
    </HBox>
  </children>
</AnchorPane>
[/XML]

Ich müsste in der Klasse FXMLController nach der Aufruf des "buttonLogin" die aktuelle Scene schliessen und eine neue Scene öffnen. Nur wie mache ich das? Komme ich von der FXMLController Klasse irgendwie an die Stage aus der App Klasse? Der FXMLController wird ja durch den FXMLLoader geladen, so dass ich keine Referenz übergeben kann.

Hat jemand eine Idee? Oder bin ich gar völlig auf dem Holzweg?

Viele Grüße

Markus


----------



## BlackC (18. Dez 2012)

Am einfachsten ist, du ersetzt die aktuelle scene (dein Login) mit der neuen. Die stage ist ja deine Applikation, die jeweils nur eine scene hat. Um jetzt diese zu wechseln, muss du in deiner Main-Klasse (App ) eine entsprechende Methode schreiben. Diese rufst du dann beim Klick auf dein Loginbutton auf. Deinem Controller vom LoginView kannst du ja der Main-Klasse übergeben.

Ich poste mal meinen Code von meinem aktuellen Projekt. Hoffe, dieser hilft dir.



```
public class Main extends Application {    
    private Stage stage;
    private final double MINIMUM_WINDOW_WIDTH = 1024.0;
    private final double MINIMUM_WINDOW_HEIGHT = 768.0;
    //private User _persowareUser =  new User();
    private String _companyName = "";
    
    // Startet die Applikation undmit goToLogin wird der Login-Bildschirm geladen
@Override
    public void start(Stage primaryStage) throws Exception {
        _companyName = getParameters().getNamed().get("NameOfCompany");
        stage = primaryStage;
        stage.setTitle("Persoware");
        stage.setMinWidth(MINIMUM_WINDOW_WIDTH);
        stage.setMinHeight(MINIMUM_WINDOW_HEIGHT);
        gotoLogin();
        primaryStage.show();
    }
    // Hier starte ich mein Hauptfenster
    public void gotoApplication(ProgressBar _progressBar) {
        try {
            _progressBar.setProgress(0.75);
            MainViewController mainView = (MainViewController) replaceSceneContent("/gui/MainView.fxml");
            _progressBar.setProgress(0.95);
            mainView.setApp(this);
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void gotoLogin() {
        try {
            final LoginViewController login = (LoginViewController) generateSceneContent("/gui/LoginView.fxml");// Pfad anpassen
            login.setApp(this);
            login.setTfFirmennameText(_companyName);
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

//    public User getPersowareUser() {
//        return _persowareUser;
//    }
//
//    public void setPersowareUser(User _persowareUser) {
//        this._persowareUser = _persowareUser;
//    }
    
    private Initializable replaceSceneContent(String fxml) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        InputStream in = Main.class.getResourceAsStream(fxml);
        loader.setBuilderFactory(new JavaFXBuilderFactory());
        loader.setLocation(Main.class.getResource(fxml));
        VBox page;
        try {
            page = (VBox) loader.load(in);
        } finally {
            in.close();
        }
        page.autosize();
        stage.getScene().setRoot(page);
        //stage.sizeToScene();
        
        return (Initializable) loader.getController();
    }
    
     private Initializable generateSceneContent(String fxml) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        InputStream in = Main.class.getResourceAsStream(fxml);
        loader.setBuilderFactory(new JavaFXBuilderFactory());
        loader.setLocation(Main.class.getResource(fxml));
        VBox page;
        try {
            page = (VBox) loader.load(in);
        } finally {
            in.close();
        }
        Scene scene = new Scene(page, 1024, 768);
        scene.getStylesheets().add("/data/style/persoware.css");
        stage.setResizable(true);
        stage.setScene(scene);        
        stage.sizeToScene();
        return (Initializable) loader.getController();
        
    }
     
    public String getCompanyName(){
        return this._companyName;
    }
   
    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
```

Würde dir gern auch noch das Tutorial von Oracle empfehlen, dass  hat mir zumindest gut geholfen und löst auch dein beschriebenes Problem, falls du mit meiner Lösung nicht klar kommen solltest.


----------



## MarkusM (19. Dez 2012)

Vielen Dank, das Beispiel schaue ich mir mal in Ruhe an.

Mit den Oracle Tutorials habe ich viel Zeit verbracht, aber die Stelle zum Wechseln der Scene habe ich wohl irgendwie überlesen...


----------



## MarkusM (20. Dez 2012)

Alles klar, es funktioniert! 

Vielen Dank nochmal für das Aufzeigen des Weges! Der Zugriff auf den Controller ist aber auch wirklich gut versteckt...


----------



## BlackC (20. Dez 2012)

MarkusM hat gesagt.:


> Alles klar, es funktioniert!
> 
> Vielen Dank nochmal für das Aufzeigen des Weges! Der Zugriff auf den Controller ist aber auch wirklich gut versteckt...



Das muss ich mir wohl auf die Fahne schreiben. Wenn man es selber programmiert hat, ist einem das ja klar, wie es funktioniert und lässt dann meistens die Kommentare weg (ich zumindest). Dadurch ist es natürlich schwierig für andere , den Code nachzuvollziehen.

Aber du bist ja zurecht gekommen, dann freut es mich, das ich helfen konnte


----------



## MarkusM (20. Dez 2012)

Durch Deinen Code bin ich eigentlich ganz gut durchgestiegen. Mit versteckt meinte ich eher den JavaFX Mechanismus des FXMLLoaders, der den Zugriff auf den Controller aus meiner Sicht ganz gut "versteckt".


----------

