【发布时间】:2019-08-23 17:27:22
【问题描述】:
所以我有一个根BorderPane,一个AnchroPane 用于左侧,另一个AnchorPane 用于底部。 Left 包含一个 Button,Bottom 包含一个 Label。我想要实现的是 LeftController 的 buttonClick() 方法更新了 Bottom.fxml 并在标签上显示了一个新文本。
我已经阅读了几篇类似this 的帖子,但没有什么能让我真正解决所有问题。
这是一个虚拟项目,它代表了我更大的项目(我想对其进行重构以实现更好的 MVC 结构),我最终想了解如何在控制器之间进行通信,这对我来说现在似乎是不可能的.
我的第一个方法是在leftController 的initialize() 中创建BottomController 的新实例。这将让我访问BottomController 的setLabelText() 方法,但没有更新标签文本。尽管控制台显示我调用了该方法,但没有触及标签文本。
FXMLLoader loaderBottom = new FXMLLoader(Main.class.getResource("Bottom.fxml"));
bottom = loaderBottom.load();
bottomController = loaderBottom.getController();
我当前的方法(在我的小 dummyProject 上)让这些控制器调用其他控制器的方法是通过在 Main 的 start() 方法中初始化它们并为每个控制器添加一个 getter。
然后在控制器方面,我调用这些吸气剂以使控制器可访问..不幸的是,它以InvocationTargetException 结尾。
是否有最佳实践方法从不同的控制器类更新其他 FXML 的视图?
这是我当前方法的代码:
Main.java
public class Main extends Application {
private Stage rootStage;
private BorderPane mainWindow;
private AnchorPane left;
private AnchorPane bottom;
private MainWindowController mainWindowController;
private LeftController leftController;
private BottomController bottomController;
@Override
public void start(Stage primaryStage) throws Exception {
this.rootStage = primaryStage;
FXMLLoader loaderMainWindow = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
mainWindow = loaderMainWindow.load();
mainWindowController = loaderMainWindow.getController();
// To make the connection from the controller class to the main class
mainWindowController.setMain(this);
FXMLLoader loaderBottom = new FXMLLoader(getClass().getResource("Bottom.fxml"));
bottom = loaderBottom.load();
bottomController = loaderBottom.getController();
// To make the connection from the controller class to the main class
bottomController.setMain(this);
FXMLLoader loaderLeft = new FXMLLoader(Main.class.getResource("Left.fxml"));
left = loaderLeft.load();
leftController = loaderLeft.getController();
// To make the connection from the controller class to the main class
leftController.setMain(this);
mainWindow.setLeft(left);
mainWindow.setBottom(bottom);
Scene scene = new Scene(mainWindow);
rootStage.setScene(scene);
rootStage.show();
}
public MainWindowController getMainWindowController() { return mainWindowController;}
public LeftController getLeftController() {return leftController;}
public BottomController getBottomController() {return bottomController;}
public static void main(String[] args) {
launch(args);
}
}
LeftController.java
public class LeftController implements Initializable {
@FXML
private Button button;
private Main main;
private BottomController bottomController;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
bottomController = main.getBottomController();
}
@FXML
public void buttonClick(javafx.event.ActionEvent actionEvent) {
System.out.println("Some Stuff..");
bottomController.setLabelText("Some Stuff..");
}
public void setMain(Main main) {
this.main = main;
}
}
BottomController.java
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ResourceBundle;
public class BottomController implements Initializable {
@FXML
private Label label;
private Main main;
private LeftController leftController;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
@FXML
public void setLabelText(String text) {
label.setText(text);
}
public void setMain(Main main) {
this.main = main;
}
}
Left.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="100.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LeftController">
<children>
<Button fx:id="button" layoutX="237.0" layoutY="169.0" mnemonicParsing="false" onAction="#buttonClick" text="Button" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
</children>
</AnchorPane>
底部.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.BottomController">
<children>
<Label fx:id="label" alignment="CENTER" layoutX="203.0" layoutY="304.0" prefHeight="30.0" text="Label" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0" />
</children>
</AnchorPane>
例外:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javafx.fxml.LoadException:
/C:/Users/Ruphus/IdeaProjects/controllerAccess/out/production/controllerAccess/sample/Left.fxml
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
at sample.Main.start(Main.java:39)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Caused by: java.lang.NullPointerException
at sample.LeftController.initialize(LeftController.java:22)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
... 12 more
Exception running application sample.Main
所以我期望以下步骤顺序:
首先:调用Main的start()方法(除了main())。
第二:start() 调用 setMain() 方法,从而使控制器可以访问 Main 类
第三:调用LeftController 的初始化以检索BottomController 的引用以使其可用。
第四:单击按钮并更改标签文本。
我对错误跟踪感到非常困惑,因为它会将我导航到main 内的left = loaderLeft.load();。如果我注释该行以检索 LeftController 中的 BottomController ,我可以毫无错误地开始。所以我必须假设控制器 initialize() 方法在 start() 方法之前被调用?
【问题讨论】:
-
@M.leRutte 我不这么认为,因为我遇到了
InvocationTargetException -
java.lang.reflect.InvocationTargetException-->Caused by: java.lang.RuntimeException-->Caused by: javafx.fxml.LoadException-->Caused by: java.lang.NullPointerException -
啊 oups :D 但这对我没有帮助。我非常了解 NPE 是什么,但我看不出我的代码存在问题。
-
我猜
initialize被称为之前setMain?
标签: java javafx view controller label