简体   繁体   中英

JavaFx actions between controllers

How i can do button action for editing TableView . I need to put text from TextArea to table when i touch button. And if put System.out.println in inputToTable() it is work.

public class InputController {

    public TextArea inputArea;
    public Button inputButton;
    private TableController tableController;

    public void initialize() {
        tableControllerInit();
    }

    public void inputToTable() {
        if(inputArea.getText() != "") {
            tableController.tableInfo.setItems(FXCollections.observableArrayList(new InputObject(inputArea.getText())));
        }
    }

    private void tableControllerInit() {
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("table.fxml"));
            fxmlLoader.load();
            tableController = fxmlLoader.getController();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class TableController {

    @FXML TableView<InputObject> tableInfo;
    @FXML TableColumn<InputObject, String> col1;

    public void initialize() {
        col1.setCellValueFactory(new PropertyValueFactory<>("text"));
    }
}

public class Controller implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    }
}

public class InputObject {
    String text;

    public InputObject(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}



<BorderPane fx:controller="sample.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <left>
       <fx:include source="table.fxml"/>
   </left>
   <center>
      <fx:include source="input.fxml"/>
   </center>
</BorderPane>

<TableView fx:controller="sample.TableController" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:id="tableInfo" prefHeight="400.0" prefWidth="330.0">
    <columns>
        <TableColumn fx:id="col1" prefWidth="75.0" text="Output" />
    </columns>
    <columnResizePolicy>
        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
    </columnResizePolicy>
</TableView>

<VBox fx:controller="sample.InputController" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" alignment="TOP_CENTER" prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
    <children>
        <TextArea fx:id="inputArea" prefHeight="188.0" prefWidth="270.0" />
        <Button fx:id="inputButton" onAction="#inputToTable" mnemonicParsing="false" text="Input">
            <VBox.margin>
                <Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
            </VBox.margin>
        </Button>
    </children>
</VBox>

You load table.fxml twice: once via the fx:include in the main FXML file, and once in InputController , via the FXMLLoader you create in the tableControllerInit() method. Consequently, two instances of TableController are created, one associated with the first UI you load from table.fxml , and one associated with the second UI you load from table.fxml .

The UI you load via the fx:include is displayed in the VBox defined in the main FXML file. The UI you load with the FXMLLoader is never displayed (in fact, you never even keep a reference to it, you just call loader.load() and discard the result). When you try to update the table's items (do you really intend to replace all the existing items, by the way?), you refer to the second controller instance, which is associated with the UI which is never displayed. Consequently, you are updating a table that is not displayed, and you never see any results.

What you really need to do is share the same data between the two controllers associated with the two fx:include s. You can do this simply by injecting those two controllers into the main controller, as described in the "Nested Controllers" section in the documentation.

First, give the fx:include elements fx:id attributes:

<BorderPane fx:controller="sample.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <left>
       <fx:include fx:id="table" source="table.fxml"/>
   </left>
   <center>
      <fx:include fx:id="input" source="input.fxml"/>
   </center>
</BorderPane>

Then you can inject the controllers into the main controller by creating fields with the word "Controller" appended to the fx:id . Create a single observable list, which will represent the list of items displayed in the table, and pass it to each controller:

public class Controller implements Initializable {

    @FXML
    private TableController tableController ;

    @FXML
    private InputController inputController ;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ObservableList<InputObject> items = FXCollections.observableArrayList();
        tableController.setTableItems(items);
        inputController.setTableItems(items);
    }
}

Finally, just define the obvious methods in each of the other two controllers:

public class TableController {

    @FXML 
    private TableView<InputObject> tableInfo;
    @FXML 
    private TableColumn<InputObject, String> col1;

    public void initialize() {
        col1.setCellValueFactory(new PropertyValueFactory<>("text"));
    }

    public void setTableItems(ObservableList<InputObject> tableItems) {
        tableInfo.setItems(tableItems);
    }
}

Now the table is displaying the contents of the items list created in the main controller's initalize() method, and the InputController has a reference to the same list. So all you need to do is update that list in the InputController . I assume you just want to add items to the table (not replace them all):

public class InputController {

    @FXML
    private TextArea inputArea;
    @FXML
    private Button inputButton;

    private ObservableList<InputObject> tableItems ;

    public void setTableItems(ObservableList<InputObject> tableItems) {
        this.tableItems = tableItems ;
    }

    public void inputToTable() {
        if(! inputArea.getText().isEmpty()) {
            tableItems.add(new InputObject(inputArea.getText()));
        }
    }


}

More generally, if you have more data to share among the different controllers, you would create one or more "model" classes and share a model instance with the controllers. Then you can observe the properties of the model and update them. See Applying MVC With JavaFx for a more comprehensive example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM