What I'm trying to do
Load a stylesheet and apply it to the scene when a user clicks on a button
The issue
Calling getScene()
returns null.
The class the function is in is the controller and root node of the scene, I'm using Scenebuilder 2.0 and have set the class to be the controller of the loaded fxml, it is a VBox
.
VBox guiRootNode = null; // inside this instance is where the `getScene() call is`
try {
FXMLLoader loader = new FXMLLoader(MainWindow.class.getResource("MainWindow.fxml"));
guiRootNode = (VBox) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
if (guiRootNode == null) {
new Alert(Alert.AlertType.ERROR, "The GUI could not be loaded").showAndWait();
Platform.exit();
} else {
primaryStage.setScene(new Scene(guiRootNode));
}
The problem code is a member function inside the MainWindow
class, the @FXML
tag is so I can set the button to call it onAction()
via the MainWindow.fxml
.
@FXML
private void onDefaultCssClicked()
{
// getScene() returns null
getScene().getStylesheets().remove(getClass().getResource("dark.css").toExternalForm());
getScene().getStylesheets().add(getClass().getResource("default.css").toExternalForm());
}
The complete code can be found at https://github.com/SebastianTroy/FactorioManufacturingPlanner however it doesn't represent a minimal code example by a long shot...
Similar Questions
JavaFX - getScene() returns null This QA assumes the getScene()
call was done in an initialise
function or during instantiation.
JavaFX getScene() returns null in initialize method of the controller In this QA the call is specifically in the initialise
method, so not applicable here.
Things I have tried
- I am not using the
fx:root
construct, checking that option in SceneBuilder causes the errorjavafx.fxml.LoadException: Root hasn't been set. Use method setRoot() before load.
- Calling
button.getScene()
works fine, so I have my hack, but I'd like to understand the problem anyway.
Resolution
I stopped trying to make my controller the root gui object.
Basically I had asumed that the controller for a FX gui was the root GUI node, hence me making the controller extend the type of the root gui node. this of course isn't the case, the controller is and should be a seperate class which has some of the gui variables injected into it.
MCVE
MainWindow.fxml
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.gui.MainWindow">
<children>
<Button onAction="#click" text="button" fx:id="button"/>
</children>
</VBox>
MainWindow.java
public class MainWindow extends VBox {
@FXML
private Button button;
@FXML
private void click() {
System.out.println("Controller scene: "+ getScene());
System.out.println("Button scene: "+ button.getScene());
}
}
Output on button click
Controller scene: null
Button scene: javafx.scene.Scene@4d6ed40a