java - 如何从第二个 Controller 将值传递到已打开的阶段(第一个 Controller )?

标签 java javafx tableview fxml fxmlloader

我有两个 Controller

  1. FXMLDocumentControllerTableView CustomerTable。
  2. NewCustomerController 第二个 Controller ,用于添加新行。

这是我的代码

FXMLDocument.fxml

<AnchorPane id="AnchorPane" prefHeight="283.0" prefWidth="437.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mytableview.FXMLDocumentController">
    <children>
        <Button fx:id="button" layoutX="309.0" layoutY="25.0" onAction="#handleButtonAction" text="New Customer" />
      <TableView fx:id="customerTable" layoutX="6.0" layoutY="61.0" prefHeight="215.0" prefWidth="426.0">
        <columns>
          <TableColumn fx:id="custname" prefWidth="75.0" text="Customer Name" />
          <TableColumn fx:id="city" prefWidth="75.0" text="City" />
        </columns>
         <columnResizePolicy>
            <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
         </columnResizePolicy>
      </TableView>
    </children>
</AnchorPane>  

NewCustomer.fxml

<AnchorPane id="AnchorPane" prefHeight="172.0" prefWidth="209.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="com.newcustomer.NewCustomerController">
   <children>
      <Button layoutX="141.0" layoutY="129.0" mnemonicParsing="false" onAction="#newCustomer" text="Add" />
      <TextField fx:id="cNameTextField" layoutX="14.0" layoutY="26.0" promptText="Customer Name" />
      <TextField fx:id="custCityTextField" layoutX="14.0" layoutY="77.0" promptText="City" />
   </children>
</AnchorPane>

FXMLDocumentController.java

public class FXMLDocumentController implements Initializable {

private FXMLDocumentController documentController; //updated

@FXML
public TableView<Customer> customerTable;

@FXML
public TableColumn<Customer, String> custname;

@FXML
public TableColumn<Customer, String> city;  

@Override
public void initialize(URL url, ResourceBundle rb) { //updated
    custname.setCellValueFactory(new PropertyValueFactory<>("name"));
    city.setCellValueFactory(new PropertyValueFactory<>("city"));           
}

@FXML
private void handleButtonAction(ActionEvent event) throws IOException {
    Parent parent = FXMLLoader.load(getClass().getResource("/com/newcustomer/NewCustomer.fxml"));
    controller.setFXMLDocumentController(documentController); //updated
    Stage stage = new Stage();
    Scene scene = new Scene(parent);
    stage.setScene(scene);
    stage.show();
}

public void inflateUI(Customer customer) {
    custname.setCellValueFactory(new PropertyValueFactory<>("name"));
    city.setCellValueFactory(new PropertyValueFactory<>("city"));
    customerTable.getItems().add(customer);
}

NewCustomerController.java

public class NewCustomerController implements Initializable { 

 private FXMLDocumentController documentController; //updated

@FXML
private TextField cNameTextField;

@FXML
private TextField custCityTextField;

@Override
public void initialize(URL url, ResourceBundle rb) {
}
    public void setFXMLDocumentController(FXMLDocumentController fXMLDocumentController) { //updated
    this.documentController = fXMLDocumentController;
}

public void newCustomer(ActionEvent e) throws IOException {
    String name = cNameTextField.getText();
    String stringCity = custCityTextField.getText();

    Customer customer = new Customer(10, name, stringCity);
    FXMLLoader fXMLLoader = new FXMLLoader(getClass().getResource("/mytableview/FXMLDocument.fxml"));
    documentController = fXMLLoader.<FXMLDocumentController>getController(); //Newly updated
    documentController.inflateUI(customer); // Newly updated 
    }

}

MyTableView.java

public class MyTableView extends Application {

    public MyTableView() {
    }

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

I want a row to be added in a TableView but it does not working.
What the exact I've missed?

最佳答案

首先,我建议通过@kleopatra提供的链接来了解 Controller 之间通信的概念。

谈到您的实际问题,我注意到您的代码中存在三个问题。其中,@kleopatra 已经指定了一个。

关于您在 newCustomer() 方法中获得的 NPE,您启动了 FXMLLoader 实例但未加载它。因此 getController() 为 null。要解决此问题,您需要先调用 load() 方法,然后再调用 getController()。

public void newCustomer(ActionEvent e) throws IOException {
    String name = cNameTextField.getText();
    String stringCity = custCityTextField.getText();
    Customer customer = new Customer(10, name, stringCity);
    FXMLLoader fXMLLoader = new FXMLLoader(getClass().getResource("/mytableview/FXMLDocument.fxml"));
    fXMLLoader.load(); // YOU ARE MISSING THIS LINE
    FXMLDocumentController fXMLDocumentController = fXMLLoader.<FXMLDocumentController>getController();
    fXMLDocumentController.inflateUI(customer); // Getting NPE at this line.
}

但是,上述修复是无用的,因为您正在创建一个未被使用的 FXMLDocumentController 的新实例(如 @kleopatra 所指定)。您必须实际传递要与之通信的 Controller 实例。您需要在 NewCustomerController 中创建该 Controller 的实例变量并对其进行设置。

@FXML
private void handleButtonAction(ActionEvent event) throws IOException {
    FXMLLoader fXMLLoader = new FXMLLoader(getClass().getResource("/com/newcustomer/NewCustomer.fxml"));
    Parent parent = fXMLLoader.load();
    NewCustomerController controller = fXMLLoader.getController();
    controller.setFXMLDocumentController(this); // Pass this controller to NewCustomerController
    Stage stage = new Stage();
    Scene scene = new Scene(parent);
    stage.setScene(scene);
    stage.show();
}

NewCustomerController.java

private FXMLDocumentController fXMLDocumentController;

public void setFXMLDocumentController(FXMLDocumentController fXMLDocumentController) {
    this.fXMLDocumentController = fXMLDocumentController;
}

public void newCustomer(ActionEvent e) throws IOException {
    String name = cNameTextField.getText();
    String stringCity = custCityTextField.getText();
    Customer customer = new Customer(10, name, stringCity);
    fXMLDocumentController.inflateUI(customer);//You are passing to the currently loaded controller
}

最后,您只需将 CellValueFactory 设置到 TableColumns 一次,而不是每次设置客户时。您可以将这两行移动到initialize() 方法。

@Override
public void initialize(URL url, ResourceBundle rb) {
    custname.setCellValueFactory(new PropertyValueFactory<>("name"));
    city.setCellValueFactory(new PropertyValueFactory<>("city"));
}

关于java - 如何从第二个 Controller 将值传递到已打开的阶段(第一个 Controller )?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58203401/

相关文章:

gradle - gradle/JavaFX 项目中模块 javafx.base 的两个版本

java - 为什么相机的实时预览旋转90度?

java - while循环无法停止

java - 现有类的构建器

Javafx - 应用程序类可以是 Controller 类吗

javafx - 更改不同值的图表颜色

swift:使用 UIDatePicker 从动态单元格将值发送回 UITableViewController

string - boolean 值到 TableView JavaFx 中的字符串

java - 我收到花括号错误,但我不明白为什么

iOS plist 无法从 plist 加载数据,但可以在模拟器上运行