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