I'm trying to write a GUI application in JavaFX. Basic idea is that there is a main GridPane view, and inside it - another Pane that should be changed on a button press. Since this Pane will have to read some input from user, I wanted there to be flow between Controllers so that I could pass data between different parts of the app. My idea was to keep all controllers in one place and refer to their fields from any place. It doesn't seem to be working - it seems like I cannot modify the content of a Pane from outside of it, even though I have access to its fields. It looks more or less like this:
main_view.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.MainController">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
<children>
<GridPane prefHeight="300.0" prefWidth="400.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="20.0" GridPane.rowSpan="2">
<children>
<TextField fx:id="userInputTextField">
<VBox.margin>
<Insets left="5.0" right="5.0" />
</VBox.margin>
</TextField>
<Button mnemonicParsing="false" onAction="#appendToFirstArea" text="Append to area 1" />
<Button mnemonicParsing="false" onAction="#appendToSecondArea" text="Append to area 2" />
<Button mnemonicParsing="false" onAction="#moveToFirstArea" text="Move to area 1" />
<Button mnemonicParsing="false" onAction="#moveToSecondArea" text="Move to area 2" />
</children>
<GridPane.margin>
<Insets />
</GridPane.margin>
</VBox>
<Pane fx:id="content" prefHeight="300.0" prefWidth="280.0" GridPane.columnIndex="1" GridPane.rowSpan="2" />
</children>
</GridPane>
</children>
</GridPane>
MainController.java
package main;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import java.io.IOException;
public class MainController {
public TextField userInputTextField;
public Pane content;
private FirstAreaController getFirstAreaController() {
return Main.firstAreaController;
}
private SecondAreaController getSecondAreaController() {
return Main.secondAreaController;
}
public void appendToFirstArea(ActionEvent actionEvent) {
String text = userInputTextField.getText();
getFirstAreaController().firstTextArea.appendText(text + "\n");
}
public void appendToSecondArea(ActionEvent actionEvent) {
String text = userInputTextField.getText();
getSecondAreaController().secondTextArea.appendText(text + "\n");
}
public void moveToFirstArea(ActionEvent actionEvent) {
try {
GridPane firstArea = FXMLLoader.load(getClass().getResource("first_area.fxml"));
content.getChildren().clear();
content.getChildren().add(firstArea);
} catch (IOException e) {
e.printStackTrace();
}
}
public void moveToSecondArea(ActionEvent actionEvent) {
try {
GridPane secondArea = FXMLLoader.load(getClass().getResource("second_area.fxml"));
content.getChildren().clear();
content.getChildren().add(secondArea);
} catch (IOException e) {
e.printStackTrace();
}
}
}
first_area.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane onKeyPressed="#appendTest" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity"
prefHeight="300.0" prefWidth="280.0"
xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111"
fx:controller="main.FirstAreaController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<TextArea fx:id="firstTextArea" prefHeight="200.0" prefWidth="200.0">
<GridPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</GridPane.margin>
</TextArea>
</children>
</GridPane>
FirstAreaController.java
package main;
import javafx.scene.control.TextArea;
public class FirstAreaController {
public TextArea firstTextArea;
}
second_area.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity"
prefHeight="300.0" prefWidth="280.0"
xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111"
fx:controller="main.SecondAreaController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<TextArea fx:id="secondTextArea" prefHeight="200.0" prefWidth="200.0">
<GridPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</GridPane.margin>
</TextArea>
</children>
</GridPane>
SecondAreaController.java
package main;
import javafx.scene.control.TextArea;
public class SecondAreaController {
public TextArea secondTextArea;
}
Main.java
package main;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public static MainController mainController;
public static FirstAreaController firstAreaController;
public static SecondAreaController secondAreaController;
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("main_view.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Test");
primaryStage.setScene(new Scene(root, 400, 300));
mainController = loader.getController();
FXMLLoader firstLoader = new FXMLLoader();
firstLoader.setLocation(getClass().getResource("first_area.fxml"));
firstLoader.load();
firstAreaController = firstLoader.getController();
FXMLLoader secondLoader = new FXMLLoader();
secondLoader.setLocation(getClass().getResource("second_area.fxml"));
secondLoader.load();
secondAreaController = secondLoader.getController();
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
After I press "Append to 1 area" button nothing happens - the text doesn't show up in the TextArea. Though when I add a method that is called only inside FirstAreaController
text appears in the area just as expected. How can I fix it?