【问题标题】:How to let one controller properly call a second controllers method to update the second controlers fxml/node?如何让一个控制器正确调用第二个控制器方法来更新第二个控制器 fxml/node?
【发布时间】:2019-08-23 17:27:22
【问题描述】:

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

我已经阅读了几篇类似this 的帖子,但没有什么能让我真正解决所有问题。

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

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

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

我当前的方法(在我的小 dummyProject 上)让这些控制器调用其他控制器的方法是通过在 Mainstart() 方法中初始化它们并为每个控制器添加一个 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

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


【解决方案1】:

好的,这很容易。今天我意识到,我可以将bottomController = main.getBottomController(); 部分移动到buttonClick() 方法中:

    @FXML
    public void buttonClick(javafx.event.ActionEvent actionEvent) {
        bottomController = main.getBottomController();
        System.out.println("Some Stuff..");
        bottomController.setLabelText("Some Stuff..");
    }

现在它终于按预期与标签交互了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    相关资源
    最近更新 更多