所以我有一个根 BorderPane
、一个用于左侧部分的 AnchroPane
和另一个用于底部的 AnchorPane
。左侧包含一个按钮,底部包含一个标签。我想要实现的只是 LeftController 的 buttonClick()
方法更新 Bottom.fxml 并在标签上显示新文本。
我读过一些帖子,例如 this ,但没有什么能让我真正解决所有问题。
这是一个虚拟项目,它代表了我更大的项目(我想重构它以实现更好的 MVC 结构),我最终想了解如何在 Controller 之间进行通信,这对我来说现在似乎是不可能的.
我的第一个方法是在 leftController
的 initialize()
中创建一个 BottomController
的新实例。这将使我可以访问 BottomController
的 setLabelText()
方法,但不会更新标签文本。尽管控制台显示我调用了该方法,但标签文本并未被触及。
FXMLLoader loaderBottom = new FXMLLoader(Main.class.getResource("Bottom.fxml"));
bottom = loaderBottom.load();
bottomController = loaderBottom.getController();
我当前(在我的小虚拟项目上)让这些 Controller 调用其他 Controller 的方法的方法是在 Main
的 start()
方法中初始化它们,为每个 Controller 添加一个 setter/getter 。
然后在 Controller 端,我调用这些 getter 来使 Controller 可访问。不幸的是,这以一些 InitationTargetException
结束。
是否有最佳实践方法可以从不同的 Controller 类更新其他 FXML View ?
这是我当前方法的代码:
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;
}
}
左.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):
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() 方法,从而使 Controller 可以访问 Main 类
第三:调用 LeftController
的初始化来检索 BottomController
的引用以使其可用。
第四:我单击按钮并更改标签文本。
我对错误跟踪感到非常困惑,因为它将我导航到 main
内的 left = loaderLeft.load();
。如果我注释掉用于检索 LeftController 中的 BottomController 的行,我就可以毫无错误地开始。所以我必须假设 Controller initialize()
方法在 start()
方法之前调用?
最佳答案
好吧,就这么简单。今天我意识到,我可以将 bottomController = main.getBottomController();
部分移动到 buttonClick()
方法中:
@FXML
public void buttonClick(javafx.event.ActionEvent actionEvent) {
bottomController = main.getBottomController();
System.out.println("Some Stuff..");
bottomController.setLabelText("Some Stuff..");
}
现在它终于按照预期与标签进行交互了。
关于java - 如何让一个 Controller 正确调用第二个 Controller 方法来更新第二个 Controller fxml/node?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57609329/