Chapter 10: Connecting JavaFX with Databases
Overview of Database Integration with JavaFX
Integrating JavaFX with databases allows your application to store, retrieve, and manage persistent data efficiently. JavaFX works seamlessly with JDBC (Java Database Connectivity) to perform these operations. By combining JavaFX controls like TableView
with database queries, you can create interactive, data-driven applications.
Introduction to JDBC
JDBC is an API for connecting and executing queries on databases. It allows you to:
- Establish connections to a database.
- Execute SQL queries to perform CRUD (Create, Read, Update, Delete) operations.
- Retrieve and manipulate data.
Example Application: Task Manager
Features
We’ll build a task manager application with the following features:
- Display tasks in a
TableView
. - Add new tasks to the database.
- Update tasks (toggle completion status).
- Delete tasks.
- Track when tasks are created (
created_at
) and when they are marked as completed (completed_at
).
Database Table Schema
Use the following schema for the tasks
table:
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
completed BOOLEAN NOT NULL,
created_at DATE NOT NULL,
completed_at DATE
);
Full JavaFX Application Code
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.sql.*;
import java.time.LocalDate;
public class TaskManagerApp extends Application {
// Database connection parameters
private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database_name";
private static final String DB_USER = "your_username";
private static final String DB_PASSWORD = "your_password";
// ObservableList to hold task data
private final ObservableList<Task> tasks = FXCollections.observableArrayList();
// TableView for displaying tasks
private TableView<Task> tableView;
public static class Task {
private final int id;
private String name;
private boolean completed;
private LocalDate createdAt;
private LocalDate completedAt;
public Task(int id, String name, boolean completed, LocalDate createdAt, LocalDate completedAt) {
this.id = id;
this.name = name;
this.completed = completed;
this.createdAt = createdAt;
this.completedAt = completedAt;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
public LocalDate getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDate createdAt) {
this.createdAt = createdAt;
}
public LocalDate getCompletedAt() {
return completedAt;
}
public void setCompletedAt(LocalDate completedAt) {
this.completedAt = completedAt;
}
}
@Override
public void start(Stage stage) {
VBox root = new VBox(10);
root.setPadding(new Insets(20));
// TableView setup
tableView = new TableView<>();
setupTableView();
// Load data from the database
loadTasksFromDatabase();
// Input fields and buttons for CRUD operations
TextField nameField = new TextField();
nameField.setPromptText("Task Name");
CheckBox completedCheckBox = new CheckBox("Completed");
Button addButton = new Button("Add");
addButton.setOnAction(e -> {
String name = nameField.getText().trim();
boolean completed = completedCheckBox.isSelected();
if (!name.isEmpty()) {
addTaskToDatabase(name, completed);
nameField.clear();
completedCheckBox.setSelected(false);
}
});
Button deleteButton = new Button("Delete");
deleteButton.setOnAction(e -> {
Task selectedTask = tableView.getSelectionModel().getSelectedItem();
if (selectedTask != null) {
deleteTaskFromDatabase(selectedTask);
}
});
HBox inputBox = new HBox(10, nameField, completedCheckBox, addButton, deleteButton);
root.getChildren().addAll(new Label("Task Manager"), inputBox, tableView);
// Scene setup
Scene scene = new Scene(root, 800, 400);
stage.setScene(scene);
stage.setTitle("Task Manager App");
stage.show();
}
private void setupTableView() {
TableColumn<Task, String> nameColumn = new TableColumn<>("Task Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
TableColumn<Task, Boolean> completedColumn = new TableColumn<>("Completed");
completedColumn.setCellValueFactory(new PropertyValueFactory<>("completed"));
TableColumn<Task, LocalDate> createdAtColumn = new TableColumn<>("Created At");
createdAtColumn.setCellValueFactory(new PropertyValueFactory<>("createdAt"));
TableColumn<Task, LocalDate> completedAtColumn = new TableColumn<>("Completed At");
completedAtColumn.setCellValueFactory(new PropertyValueFactory<>("completedAt"));
tableView.getColumns().addAll(nameColumn, completedColumn, createdAtColumn, completedAtColumn);
tableView.setItems(tasks);
}
private void loadTasksFromDatabase() {
try (Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM tasks")) {
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
boolean completed = resultSet.getBoolean("completed");
LocalDate createdAt = resultSet.getDate("created_at").toLocalDate();
LocalDate completedAt = resultSet.getDate("completed_at") != null
? resultSet.getDate("completed_at").toLocalDate()
: null;
tasks.add(new Task(id, name, completed, createdAt, completedAt));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void addTaskToDatabase(String name, boolean completed) {
try (Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
PreparedStatement statement = connection.prepareStatement(
"INSERT INTO tasks (name, completed, created_at, completed_at) VALUES (?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS)) {
statement.setString(1, name);
statement.setBoolean(2, completed);
statement.setDate(3, Date.valueOf(LocalDate.now()));
statement.setDate(4, completed ? Date.valueOf(LocalDate.now()) : null);
statement.executeUpdate();
// Get the generated ID and add to the ObservableList
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
int id = generatedKeys.getInt(1);
tasks.add(new Task(id, name, completed, LocalDate.now(),
completed ? LocalDate.now() : null));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void deleteTaskFromDatabase(Task task) {
try (Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
PreparedStatement statement = connection.prepareStatement("DELETE FROM tasks WHERE id = ?")) {
statement.setInt(1, task.getId());
statement.executeUpdate();
tasks.remove(task);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Explanation
Task
Class:- Represents each task with fields for
id
,name
,completed
,created_at
, andcompleted_at
.
- Represents each task with fields for
- Database Operations:
loadTasksFromDatabase()
: Reads all tasks from the database and populates theObservableList
.addTaskToDatabase()
: Inserts new tasks with the current date forcreated_at
and optionallycompleted_at
.deleteTaskFromDatabase()
: Removes a task from the database and updates theObservableList
.
TableView
:- Displays tasks dynamically with columns for all fields, including
completed_at
.
- Displays tasks dynamically with columns for all fields, including
This full implementation demonstrates a complete CRUD workflow for a task manager application using JavaFX and JDBC. Let me know if you have questions or need further enhancements!