JavaFX - 3个控制器,更改场景,无法将标签文本从A设置为B

时间:2016-12-04 12:41:03

标签: javafx controller fxml

我的问题很简单。

我有3个控制器:

  • MainController
  • 控制器
  • 控制器2

我试图告诉Controller内部,按下按钮时,请更改Controller1中的标签文字。使用MainController作为中间人。当我要求它改变到新场景同时还希望传递有关标签的信息时出现问题。

第17行的NullPointerExecption,Controller类(main.setLabel("abc");)

我没有MainController的单独FXML文件。但是我有一个单独的项目,我在使用MainController和FXML时运行代码,但是我必须使用Tabpane并创建单独的选项卡,这不是我正在寻找的。

MainController.class

package sample;

import javafx.fxml.FXML;


public class MainController {

    @FXML Controller controller1;
    @FXML Controller2 controller2;


    private void initialize() {
        System.out.println("Application started");
        controller1.init(this);
        controller2.init(this);
    }

    public void setLabel(String text) {
        System.out.println("Setting text..");
        controller2.label123.setText(text);
    }
}

Controller.class

package sample;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.Button;

import java.io.IOException;

public class Controller {

    @FXML private MainController main;
    @FXML private Button buttonSend;

    @FXML private void buttonClicked(ActionEvent event) throws IOException {
        main.setLabel("abc");
        System.out.println("Button clicked.");
        FXMLLoader loader = new FXMLLoader(getClass().getResource("sample2.fxml"));
        Parent root = loader.load();
        buttonSend.getScene().setRoot(root);
    }

    public void init(MainController mainController) {
        main = mainController;
    }
}

Controller2.class

package sample;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class Controller2 {

    private MainController main;

    @FXML public Label label123;

    public void init(MainController mainController) {
        main = mainController;
    }
}

sample.fxml (适用于Controller.class)

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.text.Font?>


<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="sample.Controller">
   <children>
      <AnchorPane prefHeight="200.0" prefWidth="200.0">
         <children>
            <Button fx:id="buttonSend" layoutX="61.0" layoutY="81.0" mnemonicParsing="false" onAction="#buttonClicked" text="Button">
               <font>
                  <Font size="18.0" />
               </font>
            </Button>
         </children>
      </AnchorPane>
   </children>
</GridPane>

sample2.fxml (对于Controller2.class)

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller2">
   <children>
      <Label fx:id="label123" layoutX="250.0" layoutY="168.0" text="Label">
         <font>
            <Font size="43.0" />
         </font>
      </Label>
   </children>
</AnchorPane>

1 个答案:

答案 0 :(得分:0)

不知何故,您需要将MainController的实例传递给控制器​​。

在这种情况下,我建议使用MainController作为工厂或创建一个&#34;知道&#34;关于MainController。您可以将有关控制器的信息传递给MainController方法中的init实例:

public interface InitializableController {
    public void init(MainController mainController);
}
public class MainController {

    private Controller controller1;

    public void setController1(Controller controller) {
        this.controller1 = controller;
    }

    private Controller2 controller2;

    public void setController2(Controller2 controller) {
        this.controller2 = controller;
    }

    public void setLabel(String text) {
        System.out.println("Setting text..");
        controller2.label123.setText(text);
    }

    public <T> T loadFXML(URL url) throws IOException {
        FXMLLoader loader = new FXMLLoader(url);
        T result = loader.load();

        // call init, if there is a controller implementing InitializableController
        Object controller = loader.getController();
        if (controller instanceof InitializableController) {
            ((InitializableController) controller).init(this);
        }

        return result;
    }

}
public class Controller implements InitializableController {

    ...

    @FXML private void buttonClicked(ActionEvent event) throws IOException {
        System.out.println("Button clicked.");
        Parent root = main.load(getClass().getResource("sample2.fxml"));
        main.setLabel("abc");
        buttonSend.getScene().setRoot(root);
    }

    @Override
    public void init(MainController mainController) {
        main = mainController;
        mainController.setController(this);
    }
}
public class Controller2 implements InitializableController {

    // private MainController main;

    @FXML public Label label123;

    @Override
    public void init(MainController mainController) {
        // main = mainController;
        mainController.setController2(this);
    }
}

请确保同时使用MainController.load方法加载第一个fxml。

BTW:我不建议让其他类直接访问其中一个控制器的字段。您可以将数据移至MainController类,并在StringProperty方法中添加text label123属性init可以绑定到MainController类。这种方式Controller2无需了解{{1}}的内部结构,因此更易于维护。