getScene()返回null,但someChild.getScene()不会

时间:2017-11-08 20:19:43

标签: javafx-8 fxml

我想做什么

加载样式表并在用户点击按钮时将其应用于场景

问题

调用getScene()将返回null。

该功能所在的类是场景的控制器根节点,我使用的是Scenebuilder 2.0并将类设置为控制器加载的fxml,它是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));
}

问题代码是MainWindow类中的成员函数,@FXML代码是,所以我可以设置按钮通过onAction()来调用它MainWindow.fxml。 / p>

@FXML
private void onDefaultCssClicked()
{
    // getScene() returns null
    getScene().getStylesheets().remove(getClass().getResource("dark.css").toExternalForm());
    getScene().getStylesheets().add(getClass().getResource("default.css").toExternalForm());
}

完整的代码可以在https://github.com/SebastianTroy/FactorioManufacturingPlanner找到,但它远远不能代表最小代码示例...

类似问题

JavaFX - getScene() returns null此质量检查假定getScene()调用是在initialise函数中或在实例化期间完成的。

JavaFX getScene() returns null in initialize method of the controller在本质量检查中,此调用专门针对initialise方法,因此不适用于此。

我尝试过的事情

  • 我没有使用fx:root构造,在SceneBuilder中检查该选项会导致错误javafx.fxml.LoadException: Root hasn't been set. Use method setRoot() before load.
  • 致电button.getScene()工作正常,所以我有我的黑客,但我还是想了解这个问题。

分辨率

我停止尝试让我的控制器成为root gui对象。

基本上我假设FX gui的控制器是根GUI节点,因此我让控制器扩展了根gui节点的类型。这当然不是这样的,控制器是并且应该是一个单独的类,其中注入了一些gui变量。

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());
    }

}

按钮上的输出单击

Controller scene: null
Button scene: javafx.scene.Scene@4d6ed40a

1 个答案:

答案 0 :(得分:3)

为fxml的根加载的VBox是与用作控制器根的实例不同的实例。您将加载的节点添加到场景中,但不将控制器添加到场景中,以便getScene()返回null

loader.getRoot() == loader.getController()

收益false

要使用与控制器和根相同的实例,请使用<fx:root>元素,并将MainWindow的实例指定为rootcontroller

<fx:root type="application.gui.MainWindow" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <Button onAction="#click" text="button" fx:id="button"/>
    </children>
</fx:root>
MainWindow mainWindow = new MainWindow();
FXMLLoader loader = new FXMLLoader(MainWindow.class.getResource("MainWindow.fxml"));
loader.setRoot(mainWindow);
loader.setController(mainWindow);
loader.load();

... new Scene(mainWindow) ...

MainWindow的构造函数中执行此操作可能很方便:

public MainWindow() {
    FXMLLoader loader = new FXMLLoader(MainWindow.class.getResource("MainWindow.fxml"));
    loader.setRoot(this);
    loader.setController(this);
    try {
        loader.load();
    } catch (IOException ex) {
        throw new IllegalStateException("cannot load fxml", ex); // or use a different kind of exception / add throws IOException to the signature
    }
}

这允许您使用MainWindow初始化+加载new MainWindow()