I have a TableView that contains entries from a database and a separate window for entering a new entry with a separate controller. The problem is that when I add a record to the database, the table scene controller doesn't know that there has been a change and the TableView is only updated after the application is restarted. How to create this connection between the controllers so that the TableView is updated immediately?
Main class.
public class ExampleApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("tableView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 700, 400);
stage.setTitle("ExampleApp");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Scene controller with a table where entries are displayed.
public class TableController {
@FXML
private Button addEntryButton;
@FXML
private TableColumn<userEntry, String> entryColumn;
@FXML
private TableView<userEntry> table;
ObservableList<userEntry> userEntries = FXCollections.observableArrayList();
@FXML
private void initialize() {
table.getItems().clear();
getAllEntriesFromDbToList();
entryColumn.setCellValueFactory(new PropertyValueFactory<userEntry, String>("entryName"));
table.setItems(userEntries);
addEntryButton.setOnAction(event -> {
openNewScene("/com/example/addNewEntryDialogue.fxml");
});
}
private void getAllEntriesFromDbToList() {
ResultSet rs = new DatabaseHandler().getEntriesTableFromDb();
try {
while (rs.next()) {
userEntries.add(new userEntry(rs.getString("entryName")
));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void openNewScene(String window) {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(window));
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Parent root = loader.getRoot();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
}
}
Dialog window controller for adding a new entry.
public class DialogueController {
@FXML
private Button inputNewEntryCancelButton;
@FXML
private Button inputNewEntryOkButton;
@FXML
private TextField inputNewEntryTextField;
@FXML
void initialize() {
inputNewEntryOkButton.setOnAction(event -> {
addNewEntryToDbTable(inputNewEntryTextField.getText());
((Node) event.getSource()).getScene().getWindow().hide();
});
inputNewEntryCancelButton.setOnAction(event -> {
((Node) event.getSource()).getScene().getWindow().hide();
});
}
private void addNewEntryToDbTable(String entryName) {
DatabaseHandler dbHandler = new DatabaseHandler();
userEntry newEntry = new userEntry(entryName);
dbHandler.addEntryToDb(newEntry);
}
}
Model. Entry class.
public class userEntry {
private String entryName;
public userEntry(String entryName) {
this.entryName = entryName;
}
public String getEntryName() {
return entryName;
}
public void setEntryName(String entryName) {
this.entryName = entryName;
}
}
Model. Data base handler class.
public class DatabaseHandler extends Configs {
Connection dbConnection;
public Connection getDbConnection() throws ClassNotFoundException, SQLException {
String connectionString = "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName;
Class.forName("com.mysql.cj.jdbc.Driver");
dbConnection = DriverManager.getConnection(connectionString, dbUser, dbPass);
return dbConnection;
}
public void addEntryToDb(userEntry task) {
String insert = "INSERT INTO " + Const.ENTRIES_TABLE + "(" +
Const.ENTRIES_ENTRY_NAME + ")" +
"VALUES(?)";
try {
PreparedStatement prSt = getDbConnection().prepareStatement(insert);
prSt.setString(1, task.getEntryName());
prSt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public ResultSet getEntriesTableFromDb() {
ResultSet resSet = null;
String select = "SELECT * FROM " + Const.ENTRIES_TABLE;
try {
resSet = getDbConnection().createStatement().executeQuery(select);
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return resSet;
}
}
View. Table scene FXML. (tableView.fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="386.0" prefWidth="248.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/18" fx:controller="com.example.tableviewtesting.TableController">
<opaqueInsets>
<Insets />
</opaqueInsets>
<bottom>
<TableView fx:id="table" maxHeight="-Infinity" prefHeight="329.0" prefWidth="248.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="entryColumn" prefWidth="247.0" text="Entries" />
</columns>
</TableView>
</bottom>
<top>
<Button fx:id="addEntryButton" mnemonicParsing="false" text="Add entry">
<BorderPane.margin>
<Insets left="10.0" top="10.0" />
</BorderPane.margin>
</Button>
</top>
</BorderPane>
View. Dialog scene FXML. (addNewEntryDialogue.fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="100.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.tableviewtesting.DialogueController">
<children>
<Label alignment="CENTER" layoutX="8.0" layoutY="18.0" prefHeight="36.0" prefWidth="70.0" text="Entry name:" />
<TextField fx:id="inputNewEntryTextField" layoutX="82.0" layoutY="16.0" prefHeight="40.0" prefWidth="208.0" />
<Button fx:id="inputNewEntryCancelButton" layoutX="156.0" layoutY="65.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="134.0" text="Cancel" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="156.0" AnchorPane.rightAnchor="10.0" />
<Button fx:id="inputNewEntryOkButton" layoutX="10.0" layoutY="70.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="134.0" text="Create new entry" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="156.0" />
</children>
</AnchorPane>