TableView de JavaFX pour afficher des données sous forme de tableau. Vous découvrirez comment créer des colonnes, lier des données, utiliser PropertyValueFactory pour lier automatiquement les propriétés, et même permettre l'édition des cellules. Le TableView est le composant idéal pour afficher des données structurées en lignes et colonnes.
6.3TableView
6.3.1 – Structure : colonnes, lignes, modèle
Le TableView est un composant JavaFX qui affiche des données sous forme de tableau avec des colonnes et des lignes. C'est l'équivalent d'un tableau HTML ou d'une grille de données. Chaque ligne représente un objet de votre modèle, et chaque colonne affiche une propriété de cet objet.
🎯 Structure d'un TableView
Un TableView est composé de plusieurs éléments :
- TableView : Le conteneur principal qui affiche le tableau
- TableColumn : Chaque colonne du tableau (une par propriété)
- Lignes : Chaque ligne représente un objet de votre modèle
- Modèle : La classe qui représente vos données (ex: Personne, Produit, etc.)
- ObservableList : La liste d'objets Ă afficher dans le tableau
Si vous utilisez des propriétés observables (StringProperty, IntegerProperty, etc.) dans votre modèle, vous devez ajouter
javafx.base dans le fichier module-info.java :opens application to javafx.graphics, javafx.fxml, javafx.base;Sinon, vous obtiendrez l'erreur : "module javafx.base cannot access class application.Personne"
📝 Créer un TableView simple
Pour créer un TableView, vous devez :
- Créer une classe modèle (ex: Personne)
- Créer des TableColumn pour chaque propriété
- Lier les colonnes aux propriétés
- Créer une ObservableList avec vos données
- Lier la liste au TableView
Exemple 1 : Classe Personne
package application;
public class Personne {
private String nom;
private String prenom;
private int age;
private String email;
public Personne(String nom, String prenom, int age, String email) {
this.nom = nom;
this.prenom = prenom;
this.age = age;
this.email = email;
}
// Getters
public String getNom() { return nom; }
public String getPrenom() { return prenom; }
public int getAge() { return age; }
public String getEmail() { return email; }
// Setters
public void setNom(String nom) { this.nom = nom; }
public void setPrenom(String prenom) { this.prenom = prenom; }
public void setAge(int age) { this.age = age; }
public void setEmail(String email) { this.email = email; }
}
Exemple 2 : TableView avec colonnes
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private TableView<Personne> tableViewPersonnes;
@FXML
private TableColumn<Personne, String> colNom;
@FXML
private TableColumn<Personne, String> colPrenom;
@FXML
private TableColumn<Personne, Integer> colAge;
@FXML
private TableColumn<Personne, String> colEmail;
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer les données
personnes = FXCollections.observableArrayList(
new Personne("Dupont", "Jean", 25, "jean@exemple.com"),
new Personne("Martin", "Marie", 30, "marie@exemple.com"),
new Personne("Bernard", "Pierre", 28, "pierre@exemple.com")
);
// Lier les colonnes aux propriétés (voir section 6.3.2 pour PropertyValueFactory)
// Pour l'instant, on définit juste les colonnes
colNom.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getNom()));
colPrenom.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getPrenom()));
colAge.setCellValueFactory(cellData -> new SimpleIntegerProperty(cellData.getValue().getAge()).asObject());
colEmail.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getEmail()));
// Définir les titres des colonnes
colNom.setText("Nom");
colPrenom.setText("Prénom");
colAge.setText("Âge");
colEmail.setText("Email");
// Lier la liste au TableView
tableViewPersonnes.setItems(personnes);
}
}
•
TableView<Personne> : TableView qui affiche des objets Personne•
TableColumn<Personne, String> : Colonne pour une propriété String de Personne•
setCellValueFactory() : Définit comment obtenir la valeur à afficher•
setItems() : Lie l'ObservableList au TableView
📝 Structure FXML
Dans le fichier FXML, vous devez définir le TableView et ses colonnes :
<TableView fx:id="tableViewPersonnes">
<columns>
<TableColumn fx:id="colNom" text="Nom" />
<TableColumn fx:id="colPrenom" text="Prénom" />
<TableColumn fx:id="colAge" text="Âge" />
<TableColumn fx:id="colEmail" text="Email" />
</columns>
</TableView>
📝 Types de colonnes
Les colonnes peuvent afficher différents types de données :
- String :
TableColumn<Personne, String> - Integer :
TableColumn<Personne, Integer> - Double :
TableColumn<Personne, Double> - Boolean :
TableColumn<Personne, Boolean> - Date :
TableColumn<Personne, LocalDate>
• Pour les types primitifs (int, double, etc.), utilisez les wrappers (Integer, Double)
• Pour Integer, utilisez
.asObject() pour convertir en IntegerProperty• Chaque colonne doit être typée correctement selon la propriété qu'elle affiche
💡 Points clés à retenir
- TableView : Composant pour afficher des données en tableau
- TableColumn : Chaque colonne représente une propriété
- setCellValueFactory() : Définit comment obtenir la valeur à afficher
- setItems() : Lie l'ObservableList au TableView
- Modèle : Créez une classe pour représenter vos données
- ObservableList : Utilisez une liste observable pour la mise Ă jour automatique
6.3.2 – PropertyValueFactory
Le PropertyValueFactory est une classe utilitaire qui simplifie la liaison des colonnes aux propriétés de votre modèle. Au lieu d'écrire manuellement le code pour extraire la valeur, vous pouvez utiliser PropertyValueFactory qui le fait automatiquement en utilisant le nom de la propriété.
🎯 Avantages de PropertyValueFactory
- Simplicité : Moins de code à écrire
- Automatique : La liaison se fait automatiquement par nom de propriété
- Maintenabilité : Plus facile à maintenir
- Standard : Méthode standard recommandée par JavaFX
📝 Utilisation de PropertyValueFactory
Au lieu d'écrire manuellement le code pour chaque colonne :
// Méthode manuelle (longue)
colNom.setCellValueFactory(cellData ->
new SimpleStringProperty(cellData.getValue().getNom())
);
// Avec PropertyValueFactory (simple)
colNom.setCellValueFactory(new PropertyValueFactory<>("nom"));
Exemple complet : TableView avec PropertyValueFactory
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private TableView<Personne> tableViewPersonnes;
@FXML
private TableColumn<Personne, String> colNom;
@FXML
private TableColumn<Personne, String> colPrenom;
@FXML
private TableColumn<Personne, Integer> colAge;
@FXML
private TableColumn<Personne, String> colEmail;
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer les données
personnes = FXCollections.observableArrayList(
new Personne("Dupont", "Jean", 25, "jean@exemple.com"),
new Personne("Martin", "Marie", 30, "marie@exemple.com"),
new Personne("Bernard", "Pierre", 28, "pierre@exemple.com"),
new Personne("Dubois", "Sophie", 32, "sophie@exemple.com")
);
// Utiliser PropertyValueFactory pour lier automatiquement
colNom.setCellValueFactory(new PropertyValueFactory<>("nom"));
colPrenom.setCellValueFactory(new PropertyValueFactory<>("prenom"));
colAge.setCellValueFactory(new PropertyValueFactory<>("age"));
colEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
// Définir les titres des colonnes
colNom.setText("Nom");
colPrenom.setText("Prénom");
colAge.setText("Âge");
colEmail.setText("Email");
// Lier la liste au TableView
tableViewPersonnes.setItems(personnes);
}
}
• PropertyValueFactory cherche une méthode getter correspondant au nom de la propriété
• Pour "nom", il cherche
getNom()• Pour "age", il cherche
getAge()• La méthode getter doit exister dans votre classe modèle
📝 Convention de nommage
PropertyValueFactory suit la convention JavaBean :
- Propriété "nom" → cherche
getNom()ounomProperty() - Propriété "age" → cherche
getAge()ouageProperty() - Propriété "email" → cherche
getEmail()ouemailProperty()
- ✅ Le nom de la propriété doit correspondre au nom du getter (sans "get" et en minuscule)
- âś… Les getters doivent suivre la convention JavaBean (get + Nom en CamelCase)
- ✅ Si vous utilisez des propriétés observables (StringProperty, etc.), PropertyValueFactory les utilisera automatiquement
- ❌ Ne pas utiliser de noms avec des majuscules au début (ex: "Nom" au lieu de "nom")
📝 Comparaison : Manuelle vs PropertyValueFactory
| Aspect | Méthode manuelle | PropertyValueFactory |
|---|---|---|
| Code | Plus de code | Moins de code |
| Simplicité | Plus complexe | Plus simple |
| Performance | Légèrement plus rapide | Légèrement plus lent (négligeable) |
| Maintenabilité | Moins maintenable | Plus maintenable |
| Recommandation | Cas spéciaux uniquement | ✅ Méthode standard |
💡 Points clés à retenir
- PropertyValueFactory : Simplifie la liaison des colonnes aux propriétés
- Convention JavaBean : Utilise les getters standard (getNom, getAge, etc.)
- Nom de propriété : Utilisez le nom en minuscule (ex: "nom", pas "Nom")
- Getters requis : Les méthodes getter doivent exister dans votre classe
- Méthode standard : C'est la méthode recommandée pour la plupart des cas
6.3.3 – TableView + modèle observable
Pour que le TableView se mette à jour automatiquement quand vous modifiez les propriétés des objets, vous devez utiliser des propriétés observables JavaFX (StringProperty, IntegerProperty, etc.) dans votre modèle. Cela permet une mise à jour en temps réel du tableau.
🎯 Pourquoi utiliser des propriétés observables ?
- Mise à jour automatique : Le TableView se met à jour quand vous modifiez une propriété
- Temps réel : Les changements sont visibles immédiatement
- Pas de refresh() : Plus besoin d'appeler refresh() manuellement
- Binding : Permet de créer des bindings avec d'autres composants
📝 Modèle avec propriétés observables
Personne.java avec propriétés observables
package application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Personne {
private StringProperty nom = new SimpleStringProperty();
private StringProperty prenom = new SimpleStringProperty();
private IntegerProperty age = new SimpleIntegerProperty();
private StringProperty email = new SimpleStringProperty();
public Personne(String nom, String prenom, int age, String email) {
this.nom.set(nom);
this.prenom.set(prenom);
this.age.set(age);
this.email.set(email);
}
// Getters pour les propriétés (nécessaires pour PropertyValueFactory)
public StringProperty nomProperty() { return nom; }
public StringProperty prenomProperty() { return prenom; }
public IntegerProperty ageProperty() { return age; }
public StringProperty emailProperty() { return email; }
// Getters classiques
public String getNom() { return nom.get(); }
public String getPrenom() { return prenom.get(); }
public int getAge() { return age.get(); }
public String getEmail() { return email.get(); }
// Setters
public void setNom(String nom) { this.nom.set(nom); }
public void setPrenom(String prenom) { this.prenom.set(prenom); }
public void setAge(int age) { this.age.set(age); }
public void setEmail(String email) { this.email.set(email); }
}
• Utilisez
StringProperty au lieu de String• Utilisez
IntegerProperty au lieu de int• Créez les méthodes
nomProperty(), ageProperty(), etc.• PropertyValueFactory utilisera automatiquement ces propriétés
📝 Utilisation avec TableView
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private TableView<Personne> tableViewPersonnes;
@FXML
private TableColumn<Personne, String> colNom;
@FXML
private TableColumn<Personne, String> colPrenom;
@FXML
private TableColumn<Personne, Integer> colAge;
@FXML
private TableColumn<Personne, String> colEmail;
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer les données
personnes = FXCollections.observableArrayList(
new Personne("Dupont", "Jean", 25, "jean@exemple.com"),
new Personne("Martin", "Marie", 30, "marie@exemple.com"),
new Personne("Bernard", "Pierre", 28, "pierre@exemple.com")
);
// PropertyValueFactory utilise automatiquement les propriétés observables
colNom.setCellValueFactory(new PropertyValueFactory<>("nom"));
colPrenom.setCellValueFactory(new PropertyValueFactory<>("prenom"));
colAge.setCellValueFactory(new PropertyValueFactory<>("age"));
colEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
// Définir les titres
colNom.setText("Nom");
colPrenom.setText("Prénom");
colAge.setText("Âge");
colEmail.setText("Email");
// Lier au TableView
tableViewPersonnes.setItems(personnes);
}
@FXML
private void modifierPersonne() {
Personne selectionnee = tableViewPersonnes.getSelectionModel().getSelectedItem();
if (selectionnee != null) {
// Modifier les propriétés
selectionnee.setNom("Nouveau nom");
selectionnee.setAge(30);
// Le TableView se met Ă jour AUTOMATIQUEMENT !
// Pas besoin d'appeler refresh()
}
}
}
• Quand vous modifiez une propriété avec
setNom(), le TableView se met à jour automatiquement• Plus besoin d'appeler
tableView.refresh()• Les changements sont visibles en temps réel
📝 Comparaison : Modèle simple vs Modèle observable
| Aspect | Modèle simple | Modèle observable |
|---|---|---|
| Types | String, int, etc. | StringProperty, IntegerProperty, etc. |
| Mise à jour | Nécessite refresh() | Automatique |
| Complexité | Plus simple | Légèrement plus complexe |
| Performance | Légèrement plus rapide | Légèrement plus lent (négligeable) |
| Recommandation | Données statiques | ✅ Données modifiables |
💡 Points clés à retenir
- Propriétés observables : Utilisez StringProperty, IntegerProperty, etc.
- Méthodes Property : Créez nomProperty(), ageProperty(), etc.
- Mise Ă jour automatique : Le TableView se met Ă jour automatiquement
- Pas de refresh() : Plus besoin d'appeler refresh() manuellement
- PropertyValueFactory : Utilise automatiquement les propriétés observables
6.3.4 – Édition de cellule (optionnel)
Par défaut, les cellules d'un TableView sont en lecture seule. Vous pouvez activer l'édition pour permettre à l'utilisateur de modifier directement les valeurs dans le tableau. Cette fonctionnalité est optionnelle et doit être activée explicitement.
🎯 Quand activer l'édition ?
- Modification directe : L'utilisateur doit pouvoir modifier les valeurs rapidement
- Interface simple : Pas besoin de formulaire séparé
- Données simples : Les données sont simples à modifier (texte, nombres)
- Expérience utilisateur : Améliore l'expérience utilisateur pour certaines applications
📝 Activer l'édition
Pour activer l'édition, vous devez :
- Activer l'édition sur le TableView
- Définir un CellFactory éditable pour chaque colonne
- Définir un OnEditCommit pour sauvegarder les modifications
Exemple : TableView avec édition
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private TableView<Personne> tableViewPersonnes;
@FXML
private TableColumn<Personne, String> colNom;
@FXML
private TableColumn<Personne, String> colPrenom;
@FXML
private TableColumn<Personne, Integer> colAge;
@FXML
private TableColumn<Personne, String> colEmail;
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer les données
personnes = FXCollections.observableArrayList(
new Personne("Dupont", "Jean", 25, "jean@exemple.com"),
new Personne("Martin", "Marie", 30, "marie@exemple.com")
);
// Configurer les colonnes avec PropertyValueFactory
colNom.setCellValueFactory(new PropertyValueFactory<>("nom"));
colPrenom.setCellValueFactory(new PropertyValueFactory<>("prenom"));
colAge.setCellValueFactory(new PropertyValueFactory<>("age"));
colEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
// Activer l'édition sur le TableView
tableViewPersonnes.setEditable(true);
// Activer l'édition pour chaque colonne
colNom.setCellFactory(TextFieldTableCell.forTableColumn());
colNom.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
personne.setNom(event.getNewValue());
});
colPrenom.setCellFactory(TextFieldTableCell.forTableColumn());
colPrenom.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
personne.setPrenom(event.getNewValue());
});
colEmail.setCellFactory(TextFieldTableCell.forTableColumn());
colEmail.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
personne.setEmail(event.getNewValue());
});
// Pour Integer, utiliser IntegerTextFieldTableCell
colAge.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
colAge.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
personne.setAge(event.getNewValue());
});
// Lier au TableView
tableViewPersonnes.setItems(personnes);
}
}
•
setEditable(true) : Active l'édition sur le TableView•
TextFieldTableCell.forTableColumn() : Crée une cellule éditable pour String•
setOnEditCommit() : Définit l'action à exécuter quand l'édition est terminée•
event.getRowValue() : Récupère l'objet de la ligne modifiée•
event.getNewValue() : Récupère la nouvelle valeur
📝 Types de cellules éditables
JavaFX fournit plusieurs types de cellules éditables :
- TextFieldTableCell : Pour les String (texte)
- CheckBoxTableCell : Pour les Boolean (cases Ă cocher)
- ChoiceBoxTableCell : Pour les choix dans une liste
- ComboBoxTableCell : Pour les choix dans une liste déroulante
Exemple : CheckBoxTableCell pour Boolean
// Si vous avez une propriété Boolean "actif"
@FXML
private TableColumn<Personne, Boolean> colActif;
// Dans initialize()
colActif.setCellValueFactory(new PropertyValueFactory<>("actif"));
colActif.setCellFactory(CheckBoxTableCell.forTableColumn(colActif));
// Pas besoin de setOnEditCommit pour CheckBox (automatique)
📝 Comment éditer une cellule
Pour éditer une cellule, l'utilisateur doit :
- Double-cliquer sur la cellule (ou appuyer sur F2)
- Modifier la valeur dans le champ de texte
- Appuyer sur Entrée pour valider (ou Échap pour annuler)
- ✅ L'édition doit être activée explicitement avec
setEditable(true) - ✅ Chaque colonne doit avoir sa propre CellFactory éditable
- âś… Utilisez
setOnEditCommit()pour sauvegarder les modifications - ✅ Pour les types non-String, utilisez un StringConverter approprié
- ❌ L'édition ne fonctionne pas si le modèle n'a pas de setters
💡 Points clés à retenir
- setEditable(true) : Active l'édition sur le TableView
- CellFactory éditable : Définit le type de cellule éditable
- setOnEditCommit() : Sauvegarde les modifications
- TextFieldTableCell : Pour les String
- CheckBoxTableCell : Pour les Boolean
- StringConverter : Pour convertir les types (Integer, Double, etc.)
- Optionnel : Utilisez seulement si nécessaire
6.3.5 – TableView avec MySQL (CRUD complet)
Dans cette section, vous allez apprendre à intégrer un TableView avec une base de données MySQL pour créer une application CRUD complète (Create, Read, Update, Delete). Vous découvrirez comment charger les données depuis MySQL, ajouter, modifier et supprimer des enregistrements, tout en gardant la synchronisation entre le TableView et la base de données.
🎯 Objectifs de cette section
- Connexion MySQL : Configurer la connexion à une base de données MySQL
- Chargement des données : Charger les données depuis MySQL dans le TableView
- CRUD complet : Implémenter toutes les opérations (Create, Read, Update, Delete)
- Synchronisation : Maintenir la synchronisation entre TableView et base de données
- Édition en cellule : Permettre l'édition directe dans le tableau avec sauvegarde automatique
📝 Configuration de la base de données
Avant de commencer, vous devez configurer votre base de données MySQL :
1. Créer la base de données et la table
personne dans phpMyAdmin avec les données d'exemple-- Création de la base de données
CREATE DATABASE IF NOT EXISTS db_javafx;
-- Utilisation de la base de données
USE db_javafx;
-- Création de la table personne
CREATE TABLE IF NOT EXISTS personne (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
prenom VARCHAR(100) NOT NULL,
age INT NOT NULL CHECK (age >= 0 AND age <= 150)
);
-- Insertion de données d'exemple
INSERT INTO personne (nom, prenom, age) VALUES
('Dupont', 'Jean', 25),
('Martin', 'Marie', 30),
('Bernard', 'Pierre', 22);
2. Classe de connexion à la base de données
package application;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DbConnexion {
private static final String DB_URL = "jdbc:mysql://localhost:3306/db_javafx";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "";
private static Connection connection = null;
// Obtient une connexion à la base de données (singleton)
public static Connection getConnection() throws SQLException {
if (connection == null || connection.isClosed()) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
} catch (ClassNotFoundException e) {
throw new SQLException("Driver MySQL non trouvé", e);
}
}
return connection;
}
// Ferme la connexion
public static void closeConnection() throws SQLException {
if (connection != null && !connection.isClosed()) {
connection.close();
}
}
}
- ✅ Téléchargez le driver MySQL Connector/J (mysql-connector-java-8.x.x.jar)
- âś… Ajoutez le driver au classpath du projet (dans le dossier
libs/) - ✅ Modifiez les paramètres de connexion (URL, USER, PASSWORD) selon votre configuration
- ✅ Le port par défaut de MySQL est 3306 (modifiez si nécessaire)
📝 Modèle avec ID
Le modèle doit inclure un ID pour identifier chaque enregistrement dans la base de données :
package application;
public class Personne {
private int id;
private String nom;
private String prenom;
private int age;
public Personne() {
this.id = 0;
this.nom = "";
this.prenom = "";
this.age = 0;
}
public Personne(int id, String nom, String prenom, int age) {
this.id = id;
this.nom = nom;
this.prenom = prenom;
this.age = age;
}
// Getters et Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public String getPrenom() { return prenom; }
public void setPrenom(String prenom) { this.prenom = prenom; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
📝 CRUD complet dans le contrôleur
1. Charger les données (Read)
// Charge toutes les personnes depuis la base de données
private void loadPersonnesFromDB() {
String sql = "SELECT id, nom, prenom, age FROM personne ORDER BY id";
try (Connection conn = DbConnexion.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
personnes.clear();
while (rs.next()) {
int id = rs.getInt("id");
String nom = rs.getString("nom");
String prenom = rs.getString("prenom");
int age = rs.getInt("age");
personnes.add(new Personne(id, nom, prenom, age));
}
} catch (SQLException e) {
showError("Erreur de chargement",
"Impossible de charger les données depuis la base de données.\n" + e.getMessage());
e.printStackTrace();
}
}
2. Ajouter une personne (Create)
// Insère une nouvelle personne dans la base de données
// L'ID est généré automatiquement par MySQL (AUTO_INCREMENT)
private void insertPersonneInDB(Personne personne) {
String sql = "INSERT INTO personne (nom, prenom, age) VALUES (?, ?, ?)";
try (Connection conn = DbConnexion.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setString(1, personne.getNom());
pstmt.setString(2, personne.getPrenom());
pstmt.setInt(3, personne.getAge());
int affectedRows = pstmt.executeUpdate();
if (affectedRows > 0) {
ResultSet generatedKeys = pstmt.getGeneratedKeys();
if (generatedKeys.next()) {
// Récupère l'ID auto-généré par MySQL
personne.setId(generatedKeys.getInt(1));
}
}
} catch (SQLException e) {
showError("Erreur d'insertion",
"Impossible d'ajouter la personne dans la base de données.\n" + e.getMessage());
e.printStackTrace();
}
}
3. Modifier une personne (Update)
// Met à jour une personne dans la base de données
private void updatePersonneInDB(Personne personne) {
String sql = "UPDATE personne SET nom = ?, prenom = ?, age = ? WHERE id = ?";
try (Connection conn = DbConnexion.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, personne.getNom());
pstmt.setString(2, personne.getPrenom());
pstmt.setInt(3, personne.getAge());
pstmt.setInt(4, personne.getId());
pstmt.executeUpdate();
} catch (SQLException e) {
showError("Erreur de mise Ă jour",
"Impossible de mettre à jour la personne dans la base de données.\n" + e.getMessage());
e.printStackTrace();
loadPersonnesFromDB(); // Recharger en cas d'erreur
}
}
4. Supprimer une personne (Delete)
// Supprime une personne de la base de données
private void deletePersonneFromDB(int id) {
String sql = "DELETE FROM personne WHERE id = ?";
try (Connection conn = DbConnexion.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id);
pstmt.executeUpdate();
} catch (SQLException e) {
showError("Erreur de suppression",
"Impossible de supprimer la personne de la base de données.\n" + e.getMessage());
e.printStackTrace();
}
}
📝 Configuration du TableView avec édition
Le TableView est configuré avec édition de cellule et synchronisation automatique avec la base de données :
@FXML
private void initialize() {
personnes = FXCollections.observableArrayList();
// Configuration des colonnes avec PropertyValueFactory
colonneId.setCellValueFactory(new PropertyValueFactory<>("id"));
colonneNom.setCellValueFactory(new PropertyValueFactory<>("nom"));
colonnePrenom.setCellValueFactory(new PropertyValueFactory<>("prenom"));
colonneAge.setCellValueFactory(new PropertyValueFactory<>("age"));
// Édition en cellule : double-clic sur une cellule pour éditer
tablePersonnes.setEditable(true);
colonneNom.setCellFactory(TextFieldTableCell.forTableColumn());
colonneNom.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
personne.setNom(event.getNewValue());
updatePersonneInDB(personne); // Synchronisation avec la BDD
});
colonnePrenom.setCellFactory(TextFieldTableCell.forTableColumn());
colonnePrenom.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
personne.setPrenom(event.getNewValue());
updatePersonneInDB(personne); // Synchronisation avec la BDD
});
// Édition de l'âge avec validation
colonneAge.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
colonneAge.setOnEditCommit(event -> {
Personne personne = event.getRowValue();
try {
int newAge = event.getNewValue();
if (newAge >= 0 && newAge <= 150) {
personne.setAge(newAge);
updatePersonneInDB(personne); // Synchronisation avec la BDD
} else {
showError("Erreur", "L'âge doit être entre 0 et 150.");
tablePersonnes.refresh();
}
} catch (Exception e) {
showError("Erreur", "L'âge doit être un nombre valide.");
tablePersonnes.refresh();
}
});
tablePersonnes.setItems(personnes);
// Charger les données depuis la base de données
loadPersonnesFromDB();
}
📝 Gestion des boutons CRUD
Bouton Ajouter
@FXML
private void handleAjouter() {
// Crée une nouvelle personne sans ID (ID sera généré par MySQL)
Personne nouvellePersonne = new Personne();
boolean okClicked = showPersonneEditDialog(nouvellePersonne, true);
if (okClicked) {
insertPersonneInDB(nouvellePersonne); // Insère dans la BDD (ID auto-généré)
personnes.add(nouvellePersonne); // Ajoute à la liste (ID déjà mis à jour)
}
}
Bouton Modifier
@FXML
private void handleModifier() {
Personne personneSelectionnee = tablePersonnes.getSelectionModel().getSelectedItem();
if (personneSelectionnee != null) {
boolean okClicked = showPersonneEditDialog(personneSelectionnee, false);
if (okClicked) {
updatePersonneInDB(personneSelectionnee); // Met Ă jour dans la BDD
tablePersonnes.refresh();
}
} else {
showWarning("Aucune sélection", "Veuillez sélectionner une personne dans la table.");
}
}
Bouton Supprimer
@FXML
private void handleSupprimer() {
int selectedIndex = tablePersonnes.getSelectionModel().getSelectedIndex();
if (selectedIndex >= 0) {
Personne personne = tablePersonnes.getSelectionModel().getSelectedItem();
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirmation");
alert.setHeaderText("Supprimer la personne");
alert.setContentText("Êtes-vous sûr de vouloir supprimer " +
personne.getNom() + " " + personne.getPrenom() + " ?");
alert.showAndWait().ifPresent(response -> {
if (response == ButtonType.OK) {
deletePersonneFromDB(personne.getId()); // Supprime de la BDD
personnes.remove(selectedIndex);
}
});
} else {
showWarning("Aucune sélection", "Veuillez sélectionner une personne dans la table.");
}
}
💡 Points clés à retenir
- Connexion MySQL : Utilisez JDBC avec le driver MySQL Connector/J
- PreparedStatement : Utilisez PreparedStatement pour éviter les injections SQL
- ID auto-généré : Utilisez AUTO_INCREMENT dans MySQL et récupérez l'ID avec getGeneratedKeys()
- Synchronisation : Chaque modification dans le TableView doit être synchronisée avec la BDD
- Édition en cellule : Utilisez setOnEditCommit() pour sauvegarder automatiquement
- Gestion d'erreurs : Affichez des messages d'erreur clairs en cas de problème
- Try-with-resources : Utilisez try-with-resources pour fermer automatiquement les connexions
Assurez-vous que votre fichier
module-info.java inclut les modules nécessaires :module Chapitre6_3_5_TableViewMySql { requires javafx.controls; requires javafx.fxml; requires java.sql; opens application to javafx.graphics, javafx.fxml, javafx.base;}