如何将值从第二个控制器传递到已经打开的 Stage(First Controller)?
How to pass values to already opened Stage(First Contrller) from Second Controller?
我有两个控制器
FXMLDocumentController
有 TableView
个 CustomerTable。
NewCustomerController
第二个控制器添加新行。
这是我的代码
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 提供的link来理解控制器之间通信的概念。
关于您的实际问题,我注意到您的代码中存在三个问题。其中,@kleopatra已经指定了一个。
关于您在 newCustomer() 方法中获得的 NPE,您启动了 FXMLLoader 实例但未加载它。由于这个原因,getController() 为空。要解决此问题,您需要先调用 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 所指定)。您必须实际传递要与之通信的控制器实例。您需要在 NewCustomerController 中创建此控制器的实例变量并设置它。
@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"));
}
我有两个控制器
FXMLDocumentController
有TableView
个 CustomerTable。NewCustomerController
第二个控制器添加新行。
这是我的代码
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 提供的link来理解控制器之间通信的概念。
关于您的实际问题,我注意到您的代码中存在三个问题。其中,@kleopatra已经指定了一个。
关于您在 newCustomer() 方法中获得的 NPE,您启动了 FXMLLoader 实例但未加载它。由于这个原因,getController() 为空。要解决此问题,您需要先调用 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 所指定)。您必须实际传递要与之通信的控制器实例。您需要在 NewCustomerController 中创建此控制器的实例变量并设置它。
@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"));
}