JAVAFX Stage über Controller weitergeben um css-file zu laden

ZarakiKen

Mitglied
Hallo,
ich versuche gerade über einen Button in einer Menüleiste ein css-file zu laden. Dafür übergebe ich die stage an meinen MainController der sie weitergibt an den MenuController. Bis hier hin funktioniert auch noch alles und meine Tests geben mir die stage auch aus und ich könnte auch hier ein css-file laden. Wenn dann aber das Programm geladen ist und ich auf den Button klicke ist die übergebene Stage null und ich bekomme eine Exception. Kann mir jemand weiter helfen und mir sagen was ich falsch mache?

MainApp
Java:
package task_reminder;


import control.MainController;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MainApp extends Application {
	
	 @Override
	 public void start(Stage stage) throws Exception {	
	     Scene scene = new Scene(FXMLLoader.load(getClass().getResource("/view/MainView.fxml")));
	     stage.setScene(scene);
	     stage.show();
	     final FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/MainView.fxml"));
	     final Parent root = (Parent)loader.load();
             MainController controller = (MainController)loader.getController();
             controller.setStage(stage); 
	 }
	  
	 public static void main(String[] args) {
	 launch(args);
	 }
	
}

MainController
Java:
package control;

import javafx.fxml.FXML;
import javafx.stage.Stage;


public class MainController {
	
     private Stage stage;
	
	 @FXML
	 private TaskController taskController;
	 @FXML
	 private MenuController menuController;
	  
	 @FXML
	 private void initialize() {
       menuController.setMainViewController(taskController);
	 }
	 

	public void setStage(Stage stage) {
       this.stage = stage;
       this.menuController.setStage(this.stage);
	 }
}

MenuController
Java:
package control;

import javafx.scene.Scene;

public class MenuController{
	
	private TaskController taskView;
	private Scene scene;	
	
	
	@FXML protected void closeApplication() {
		Platform.exit();
	}

	
	@FXML protected void changeStyles() {
		if(this.scene == null)System.out.println("NULL"); // hier ist scene null
		
	}
	
	
	public void setMainViewController(TaskController taskView) {
		this.taskView = taskView;
    }
	
   
   public void setStage(Stage stage) {
	   this.scene = stage.getScene();
	   if(this.scene != null)System.out.println("SCENE"); // prints scene
   }
}
 
Wie lautet die Exception? Sicher, dass "initialize()" mit "@FXML" annotiert wird und du dort nicht ein "@PostConstruct" möchtest?
 
Da scene Null ist während ich versuche darauf zuzugreifen bekomme ich eine NullPointerException.

Wenn ich "@PostConstruct" nutze ist scene im MenuController trotzdem NULL.

Ich habe jetzt leider nicht die Möglichkeit um alles zu posten, versuche aber morgen mal das Problem in einem kleineren Projekt nachzustellen.
 
Ich fand das Problem interessant und hab mal bischen rumgespielt:

FXML:
Code:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.canvas.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>


<BorderPane fx:id="paneFrame" prefHeight="440.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="de.test.MenueController">
   <top>
      <MenuBar fx:id="mnuMenue" BorderPane.alignment="CENTER">
        <menus>
          <Menu fx:id="mnuProgramm" mnemonicParsing="false" text="Programm">
            <items>
              <MenuItem fx:id="mnuBeenden" mnemonicParsing="false" onAction="#menueAction" text="Beenden" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Hilfe">
            <items>
              <MenuItem fx:id="mnuInfo" mnemonicParsing="false" onAction="#menueAction" text="Info" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
   </top>
   <center>
      <Canvas height="400.0" width="600.0" BorderPane.alignment="CENTER" />
   </center>
   <bottom>
      <Button fx:id="btnTest" mnemonicParsing="false" onAction="#buttonAction" text="Clicke me" BorderPane.alignment="CENTER" />
   </bottom>
</BorderPane>

Controller-Interface:
Code:
package de.test;

public interface IController {

	public void init();
	public void init2();
	public void init3();
	public void init4();
	
}

Controller:
Code:
package de.test;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;


public class MenueController implements Initializable, IController {
	
	@FXML
	private MenuItem mnuBeenden;
	@FXML
	private MenuItem mnuInfo;
	@FXML
	private Menu mnuProgramm;
	@FXML
	private MenuBar mnuMenue;
	@FXML
	private Button btnTest;
	@FXML
	private BorderPane paneFrame;
	
	
	@Override
	public void initialize(URL location, ResourceBundle resources) {
		if (mnuMenue != null) {
			Scene scene = mnuMenue.getScene();
			if (scene != null) {
				Stage stage = (Stage)scene.getWindow();
				if (stage != null) {
					System.out.println("Stage-Test 0 MenuBar");
					stage.setTitle("Test 0 MenuBar");
				}
			}
		}
		if (btnTest != null) {
			System.out.println("Button-Test 0");
		}
		if (paneFrame != null) {
			System.out.println("Pane-Test 0");
			Scene scene = paneFrame.getScene();
			if (scene != null) {
				Stage stage = (Stage)scene.getWindow();
				if (stage != null) {
					System.out.println("Stage-Test 0 Pane");
					stage.setTitle("Test 0 Pane");
				}
			}
		}
	}
	
	@Override
	public void init() {
		if (mnuMenue != null) {
			Scene scene = mnuMenue.getScene();
			if (scene != null) {
				Stage stage = (Stage)scene.getWindow();
				if (stage != null) {
					System.out.println("Stage-Test 1");
					stage.setTitle("Test 1");
				}
			}
		}
		if (btnTest != null) {
			System.out.println("Button-Test 1");
		}
		if (paneFrame != null) {
			System.out.println("Pane-Test 1");
		}		
	}

	@Override
	public void init2() {
		if (mnuMenue != null) {
			Scene scene = mnuMenue.getScene();
			if (scene != null) {
				Stage stage = (Stage)scene.getWindow();
				if (stage != null) {
					System.out.println("Stage-Test 2");
					stage.setTitle("Test 2");
				}
			}
		}
		if (btnTest != null) {
			System.out.println("Button-Test 2");
		}
		if (paneFrame != null) {
			System.out.println("Pane-Test 2");
		}
	}
	
	@Override
	public void init3() {
		if (mnuMenue != null) {
			Scene scene = mnuMenue.getScene();
			if (scene != null) {
				Stage stage = (Stage)scene.getWindow();
				if (stage != null) {
					System.out.println("Stage-Test 3");
					stage.setTitle("Test 3");
				}
			}
		}
		if (btnTest != null) {
			System.out.println("Button-Test 3");
		}
		if (paneFrame != null) {
			System.out.println("Pane-Test 3");
		}
	}
	
	@Override
	public void init4() {
		if (mnuMenue != null) {
			Scene scene = mnuMenue.getScene();
			if (scene != null) {
				Stage stage = (Stage)scene.getWindow();
				if (stage != null) {
					System.out.println("Stage-Test 4");
					stage.setTitle("Test 4");
				}
			}
		}
		if (btnTest != null) {
			System.out.println("Button-Test 4");
		}
		if (paneFrame != null) {
			System.out.println("Pane-Test 4");
		}
	}	
	
	@FXML
	public void menueAction(ActionEvent event) {
		if (event.getSource().equals(mnuInfo)) {
			System.out.println("Infos ...");
		}
		else if (event.getSource().equals(mnuBeenden)) {
			Platform.exit();
		}
		else {
			System.out.println("Unbekannte Action!");
		}
	}
	
	@FXML
	public void buttonAction(ActionEvent event) {
		if (event.getSource().equals(btnTest)) {
			System.out.println("Button clicked ...");
		}
	}
}

Main:
Code:
package de.test;
	
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {			
			//FXMLLoader fxmlLoader = new FXMLLoader();
			//Parent root = fxmlLoader.load(getClass().getResourceAsStream("/fxml/Test01.fxml"));
			
			//FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Test01.fxml"));
			FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Menue.fxml"));
			Parent root = (Parent) fxmlLoader.load();
			
			IController controller = (IController)fxmlLoader.getController();
			controller.init();
			
			Scene scene = new Scene(root);
			controller.init2();
			
			primaryStage.setScene(scene);
			controller.init3();
			
			primaryStage.show();
			controller.init4();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}

Fazit: Sobald der Stage die Scene gesetzt wird, ist sie auch im Controller verfügbar und kann über alle Nodes abgerufen werden. Und über die Scene kommt man ja bekanntlich an die Stage. Die Stage zu übergeben ist somit eigentlich nicht notwendig.
 

Zurück
Oben