JavaFX - Pane wechseln über 2. Controller

inDex

Mitglied
Hallo zusammen,

bin noch relativ unerfahren mit JavaFX und habe ein Problem welches ich auch nach mehreren Stunden
googeln nicht gelöst bekommen habe, obwohl es eine Kleinigkeit sein muss 😀

Ich habe in meiner Szene eine Splitpane, worin in der rechten Seite eine AnchorPane ("outputArea")
ist. Für diese Pane habe ich mehrere FXML Files und jeweils eigene Controller dazu.
Genau diese AnchorPane "outputArea" möchte ich über Buttons in der linken Seite der Splitpane umschalten.
Das funktioniert auch bei allen einwandfrei, aber nicht wenn ich mit einem Button innerhalb einer der versch.
Pages
in der outputArea umschalten will.

Hier der relevante Auszug des Controllers des MainWindows:

[CODE lang="java" title="MainWindowController"]public class ControllerMainWindow {
//** Panes
@FXML
private AnchorPane outputArea;

// ----------ÜBER DIESEN BUTTON FUNKTIONIERT ES!-----
public void stoerungenAction(ActionEvent actionEvent) throws IOException {
//Main.showMainPage();

FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow_MaschinenDaten.fxml"));
Parent outputPage = loader.load();
ControllerPageMaschinendaten controllerPageMaschinendaten = loader.getController();

//Anchorpane anpassen sodass outputPage sich der Größe von Parent anpasst
outputArea.getChildren().removeAll();
outputArea.getChildren().add(outputPage);
AnchorPane.setTopAnchor(outputPage, 0.0);
AnchorPane.setBottomAnchor(outputPage, 0.0);
AnchorPane.setLeftAnchor(outputPage, 0.0);
AnchorPane.setRightAnchor(outputPage, 0.0);

System.out.println("testüberLeiste");
System.out.println(outputArea);
System.out.println(outputPage);
}

public void maschDatenAction(int maschinenID) throws IOException {

FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow_MaschinenDaten.fxml"));
Parent outputPage = loader.load();
ControllerPageMaschinendaten controllerPageMaschinendaten = loader.getController();

//Anchorpane anpassen sodass outputPage sich der Größe von Parent anpasst
outputArea.getChildren().clear();
outputArea.getChildren().add(outputPage);
AnchorPane.setTopAnchor(outputPage, 0.0);
AnchorPane.setBottomAnchor(outputPage, 0.0);
AnchorPane.setLeftAnchor(outputPage, 0.0);
AnchorPane.setRightAnchor(outputPage, 0.0);


System.out.println("test Maschinen ID: " + maschinenID);
System.out.println(outputArea);
System.out.println(outputPage);
//outputArea.getChildren().clear();

//controllerPageMaschinendaten.machiwas();
}
}[/CODE]


Hier der relevante Teil aus dem Controller der geladenen Page in der outputArea:

[CODE lang="java" title="Controller der Unterseite"]public class ControllerPageMaschinenpark {

@FXML
private FlowPane fpMaschinen;

private Button[] btnMaschinen;

public void showMaschinen(){
ArrayList<Maschine> maschinenPark = Main.getMaschinenPark();
int i=1;
int anzMaschinen = Main.getMaschinenPark().size();
btnMaschinen = new Button[anzMaschinen+1];
VBox[] vBoxBtn = new VBox[anzMaschinen+1];
Label[] lblMaschinenID = new Label[anzMaschinen+1];
Label[] lblMaschinenBez = new Label[anzMaschinen+1];
ProgressBar[] prgBarMasch = new ProgressBar[anzMaschinen+1];

...


//Button Action wenn Maschine geklickt wird
for(int j=1; j<= anzMaschinen; j++)
{
btnMaschinen[j].setOnAction(e-> {

String test = ((Button) e.getSource()).getId();
System.out.println(test);

//Controller von MainWindow holen
FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
try {

loader.load();
ControllerMainWindow controllerMainWindow = loader.getController();

String maschinenID = ((Button) e.getSource()).getId();
controllerMainWindow.maschDatenAction(Integer.parseInt(maschinenID));

} catch (IOException ex) {
ex.printStackTrace();
}

});
}

}

}[/CODE]

Hier noch ein Bild des GUI für die verständlichkeit:
Error.PNG

Die Testdaten der Methode "maschDatenAction" werden ausgegeben, das heißt er schafft es bis dorthin.
Nur will die outputArea nicht aktualisiert werden 🙁
Wenn ich es bspw. über den Button "Störungen" in der Leiste links mache geht es! (selber Code Copy&Paste in ActionEvent Methode).

Ich hoffe jmd sieht den Fehler auf anhieb und kann mir weiterhelfen!
Vielen Dank vorab!
Gruß Simon
 
Das, was Du da machst, macht so doch auch gar keinen Sinn:

Java:
                FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
                try {

                    loader.load();
                    ControllerMainWindow controllerMainWindow = loader.getController();

                    String maschinenID = ((Button) e.getSource()).getId();
                    controllerMainWindow.maschDatenAction(Integer.parseInt(maschinenID));

                } catch (IOException ex) {
                    ex.printStackTrace();
                }

Du lädst ein neues "MainWindow.fxml". Dabei wird also die ganze Hierarchie an neuen Controls erstellt. Und auch ein Controller. Den Controller lässt Du Dir dann geben und machst etwas damit. Aber das ist ja alles eine ganz neue Instanz (die nicht angezeigt wird, da keine Stage und so).

Das ist also sowas wie: Du hast einen BMW. Da kannst Du auch immer ganz toll etwas in den Kofferraum packen.

Und wenn Du Deinen BMW nicht zur Hand hast, dann kaufst Du Dir einfach einen ganz neuen. Der hat dann auch einen Kofferraum. Und da packst Du dann etwas rein. (Und da Du auf die Instanzen keine Referenz hältst, bedeutet das: Du packst den Schlüssel ins Auto und machst ein Zettel dran: Müllabfuhr: bitte entsorgen!)
Und dann wunderst Du Dich, dass am Ende in Deinem BMW der Inhalt des Kofferraums unverändert ist - Du hast doch in den anderen Kofferraum etwas rein getan!

Also was wäre hier die Lösungsidee? Ganz trivial: Wenn Du im ControllerMainWindow den Inhalt der Seite erzeugst, dann gibst Du dem erzeugten Controller der auch eine Referenz auf den ControllerMainWindow. Dann kannst Du eine Methode aufrufen, die den Inhalt entsprechend tauscht.
Oder um da von der konkreten Implementierung evtl. etwas unabhängiger zu werden: Du machst ein kleines Interface mit der Wechsel-Methode, ControllerMainWindow implementiert dieses Interface und dann will der Controller der Anzeige einfach eine Instanz des Interfaces. Aber das ist von der Funktionalität erst einmal egal.
 
Und wenn Du Deinen BMW nicht zur Hand hast, dann kaufst Du Dir einfach einen ganz neuen. Der hat dann auch einen Kofferraum. Und da packst Du dann etwas rein. (Und da Du auf die Instanzen keine Referenz hältst, bedeutet das: Du packst den Schlüssel ins Auto und machst ein Zettel dran: Müllabfuhr: bitte entsorgen!)
Und dann wunderst Du Dich, dass am Ende in Deinem BMW der Inhalt des Kofferraums unverändert ist - Du hast doch in den anderen Kofferraum etwas rein getan!
der Vergleich ist super 👍
 
Zuerst einmal Danke für die schnelle Antwort!

Okay das war mir so gar nicht klar 😀
Ich dachte mit -> loader.getController(); bekomme ich über das entsprechende FXML den Controller bzw.
die Referenz davon. Das habe ich jetzt soweit verstanden und werde versuchen alles um zu schreiben sodass ich jeweils
nur eine Instanz und die Referenz darauf habe.
Was mir jetzt nicht ganz klar wurde, wie tausche ich die Controller und den Zugriff auf deren Informationen/Methoden
untereinander aus? Ein kleines Code Beispiel würde mir sehr helfen, falls nicht zu viel verlangt 😁
 
Alle Methoden zum Öffnen der jeweiligen Seiten sind im ControllerMainWindow ... Die Methode passt Du so in der Art an:

[CODE lang="java" highlight="11"]public class ControllerMainWindow {

...

public void stoerungenAction(ActionEvent actionEvent) throws IOException {
//Main.showMainPage();

FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow_MaschinenDaten.fxml"));
Parent outputPage = loader.load();
ControllerPageMaschinendaten controllerPageMaschinendaten = loader.getController();
controllerPageMaschinendaten.setControllerMainWindow(this);

//Anchorpane anpassen sodass outputPage sich der Größe von Parent anpasst

...

[/CODE]

Das natürlich bei allen Seitenteilen.

Wenn dann aus dem Seitenteil ein entsprechender Wechsel kommen soll, dann kannst Du controllerMainWindow.stoerungenAction(null) aufrufen.
(Bzw. die Methode umschreiben. Das wäre eher etwas wie:
Java:
    public void stoerungenAction(ActionEvent actionEvent) throws IOException {
        openMaschinenDaten();
    }

    public void openMaschinenDaten() {
        FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow_MaschinenDaten.fxml"));
        Parent outputPage = loader.load();
        ControllerPageMaschinendaten controllerPageMaschinendaten = loader.getController();
        controllerPageMaschinendaten.setControllerMainWindow(this);
        
        //Anchorpane anpassen sodass outputPage sich der Größe von Parent anpasst

...

Damit das aber funktioniert, musst Du natürlich in den anderen Controllern die instanzvariable mit Setter einfügen:
Java:
    ControllerMainWindow controllerMainWindow;
    
    public void setControllerMainWindow(ControllerMainWindow controllerMainWindow) {
        this.controllerMainWindow = controllerMainWindow;
    }
 

Zurück
Oben