java - 如何让一个 Controller 正确调用第二个 Controller 方法来更新第二个 Controller fxml/node?

标签 java javafx view controller label

所以我有一个根 BorderPane、一个用于左侧部分的 AnchroPane 和另一个用于底部的 AnchorPane。左侧包含一个按钮,底部包含一个标签。我想要实现的只是 LeftController 的 buttonClick() 方法更新 Bottom.fxml 并在标签上显示新文本。

我读过一些帖子,例如 this ,但没有什么能让我真正解决所有问题。

这是一个虚拟项目,它代表了我更大的项目(我想重构它以实现更好的 MVC 结构),我最终想了解如何在 Controller 之间进行通信,这对我来说现在似乎是不可能的.

我的第一个方法是在 leftControllerinitialize() 中创建一个 BottomController 的新实例。这将使我可以访问 BottomControllersetLabelText() 方法,但不会更新标签文本。尽管控制台显示我调用了该方法,但标签文本并未被触及。

FXMLLoader loaderBottom = new FXMLLoader(Main.class.getResource("Bottom.fxml"));
bottom = loaderBottom.load();
bottomController = loaderBottom.getController();

我当前(在我的小虚拟项目上)让这些 Controller 调用其他 Controller 的方法的方法是在 Mainstart() 方法中初始化它们,为每个 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

所以我期望以下步骤顺序: 首先:调用 Mainstart() 方法(除了 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/

相关文章:

javafx.scene.layout.Pane 无法转换为 javafx.fxml.FXMLLoader

JavaFX TableView - 将表格列的内容居中

android - 如何在同一个 onclicklistener 中连接多个按钮?

asp.net-mvc - 在 POST View 后返回 GET View 失败 ASP.NET MVC

list - Delphi:用于在 ListView 中绘图的数据存储

java - 在 Java 中查找具有不同数据类型的最大 3 个数字

java - 如何使用用户名/密码(无证书)通过 https 设置 CXF/SOAP 客户端连接

java - 为什么应用程序重新启动时该值没有保存到 SharedPreferences 中?

java - 如何等待一个长进程的结束(在另一个线程上)?

java - 性能问题 - 清除并重用一个集合或扔掉它并获得一个新的