getScene() returns 为空,但 someChild.getScene() 没有
getScene() returns null, but someChild.getScene() doesn't
我想做什么
加载样式表并在用户单击按钮时将其应用于场景
问题
正在调用 getScene()
returns 空。
class函数所在的是场景的控制器和根节点,我用的是Scenebuilder 2.0 并将 class 设置为加载的 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
class 中的一个成员函数,@FXML
标签是这样我可以设置按钮通过 onAction()
调用它 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());
}
可以在 https://github.com/SebastianTroy/FactorioManufacturingPlanner 找到完整的代码,但是从长远来看它并不代表最小的代码示例...
类似问题
此 QA 假定 getScene()
调用是在 initialise
函数中或在实例化期间完成的。
在此 QA 中,调用专门在 initialise
方法中,因此此处不适用。
我尝试过的东西
- 我没有使用
fx:root
构造,在 SceneBuilder 中检查该选项会导致错误 javafx.fxml.LoadException: Root hasn't been set. Use method setRoot() before load.
- 调用
button.getScene()
工作正常,所以我有技巧,但我还是想了解问题所在。
分辨率
我不再尝试让我的控制器成为根 gui 对象。
基本上我假设 FX gui 的控制器是根 GUI 节点,因此我让控制器扩展了根 gui 节点的类型。这当然不是这种情况,控制器是并且应该是一个单独的 class,其中注入了一些 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
为 fxml 的根加载的 VBox
与用作控制器根的实例不同。您将加载的节点添加到场景中,但没有将控制器添加到场景中,因此 getScene()
returns null
.
loader.getRoot() == loader.getController()
产量 false
.
要使用与控制器和根相同的实例,请使用 <fx:root>
元素并将 MainWindow
的实例指定为 root
和 controller
:
<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
}
}
这允许您使用 new MainWindow()
.
初始化+加载 MainWindow
我想做什么
加载样式表并在用户单击按钮时将其应用于场景
问题
正在调用 getScene()
returns 空。
class函数所在的是场景的控制器和根节点,我用的是Scenebuilder 2.0 并将 class 设置为加载的 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
class 中的一个成员函数,@FXML
标签是这样我可以设置按钮通过 onAction()
调用它 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());
}
可以在 https://github.com/SebastianTroy/FactorioManufacturingPlanner 找到完整的代码,但是从长远来看它并不代表最小的代码示例...
类似问题
getScene()
调用是在 initialise
函数中或在实例化期间完成的。
initialise
方法中,因此此处不适用。
我尝试过的东西
- 我没有使用
fx:root
构造,在 SceneBuilder 中检查该选项会导致错误javafx.fxml.LoadException: Root hasn't been set. Use method setRoot() before load.
- 调用
button.getScene()
工作正常,所以我有技巧,但我还是想了解问题所在。
分辨率
我不再尝试让我的控制器成为根 gui 对象。
基本上我假设 FX gui 的控制器是根 GUI 节点,因此我让控制器扩展了根 gui 节点的类型。这当然不是这种情况,控制器是并且应该是一个单独的 class,其中注入了一些 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
为 fxml 的根加载的 VBox
与用作控制器根的实例不同。您将加载的节点添加到场景中,但没有将控制器添加到场景中,因此 getScene()
returns null
.
loader.getRoot() == loader.getController()
产量 false
.
要使用与控制器和根相同的实例,请使用 <fx:root>
元素并将 MainWindow
的实例指定为 root
和 controller
:
<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
}
}
这允许您使用 new MainWindow()
.
MainWindow