ObservableList. Les collections observables sont essentielles pour créer des interfaces utilisateur réactives qui se mettent à jour automatiquement lorsque les données changent. Vous apprendrez à créer, manipuler et lier des ObservableList à vos composants JavaFX.
6.1Collections observables
6.1.1 – ObservableList
ObservableList est une interface JavaFX qui étend l'interface List de Java et ajoute la capacité d'observer les changements dans la liste. Quand vous modifiez une ObservableList (ajout, suppression, modification d'éléments), tous les composants JavaFX qui l'utilisent sont automatiquement mis à jour.
🎯 Pourquoi utiliser ObservableList ?
Contrairement Ă une List normale, une ObservableList permet :
- Mise Ă jour automatique : Les composants JavaFX (ListView, TableView, etc.) se mettent Ă jour automatiquement quand la liste change
- Écoute des changements : Vous pouvez écouter les modifications pour réagir aux changements
- Liaison de données : Créer des liens bidirectionnels entre les données et l'interface
- Moins de code : Plus besoin d'appeler manuellement
refresh()sur les composants
ObservableList au lieu de List quand vous travaillez avec des composants JavaFX comme ListView, TableView, ou ComboBox. C'est la clé pour avoir des interfaces réactives !
📝 Créer une ObservableList
Pour créer une ObservableList, utilisez la classe FXCollections :
Exemple 1 : Créer une ObservableList vide
package application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
// Créer une ObservableList vide
private ObservableList<String> items = FXCollections.observableArrayList();
// Ou avec initialisation
private ObservableList<String> noms = FXCollections.observableArrayList(
"Jean", "Marie", "Pierre", "Sophie"
);
}
•
FXCollections.observableArrayList() : Crée une ObservableList vide•
FXCollections.observableArrayList(...) : Crée une ObservableList avec des éléments initiaux• Le type entre
<> définit le type des éléments (String, Personne, etc.)
Exemple 2 : Créer une ObservableList à partir d'une List existante
package application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.ArrayList;
import java.util.List;
public class MainController {
public void exempleConversion() {
// Liste normale
List<String> listeNormale = new ArrayList<>();
listeNormale.add("Élément 1");
listeNormale.add("Élément 2");
listeNormale.add("Élément 3");
// Convertir en ObservableList
ObservableList<String> observableList = FXCollections.observableArrayList(listeNormale);
// Maintenant observableList est une ObservableList avec les mêmes éléments
}
}
📝 Utiliser ObservableList avec ListView
L'utilisation principale d'ObservableList est avec des composants comme ListView. Voici comment lier une ObservableList Ă une ListView :
Exemple complet : ListView avec ObservableList
MainController.java
package application;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private ListView<String> listViewItems;
@FXML
private TextField txtNouvelItem;
@FXML
private Button btnAjouter;
// ObservableList pour stocker les éléments
private ObservableList<String> items;
@FXML
private void initialize() {
// Créer l'ObservableList avec des éléments initiaux
items = FXCollections.observableArrayList(
"Pomme", "Banane", "Orange", "Fraise"
);
// Lier l'ObservableList Ă la ListView
listViewItems.setItems(items);
// Maintenant, toute modification de 'items' sera automatiquement
// reflétée dans la ListView !
}
@FXML
private void ajouterItem() {
String nouvelItem = txtNouvelItem.getText().trim();
if (!nouvelItem.isEmpty()) {
// Ajouter Ă l'ObservableList
items.add(nouvelItem);
// La ListView se met Ă jour AUTOMATIQUEMENT !
// Pas besoin d'appeler listViewItems.refresh()
txtNouvelItem.clear();
}
}
@FXML
private void supprimerItem() {
String itemSelectionne = listViewItems.getSelectionModel().getSelectedItem();
if (itemSelectionne != null) {
// Supprimer de l'ObservableList
items.remove(itemSelectionne);
// La ListView se met Ă jour AUTOMATIQUEMENT !
}
}
}
•
items est une ObservableList<String>•
listViewItems.setItems(items) : Lie la ListView à l'ObservableList• Quand vous ajoutez/supprimez dans
items, la ListView se met à jour automatiquement• Pas besoin d'appeler
refresh() manuellement !
📝 Écouter les changements dans une ObservableList
Vous pouvez écouter les changements dans une ObservableList en ajoutant un ListChangeListener :
Exemple : Écouter les modifications
@FXML
private void initialize() {
items = FXCollections.observableArrayList();
listViewItems.setItems(items);
// Ajouter un listener pour écouter les changements
items.addListener((javafx.collections.ListChangeListener.Change<? extends String> change) -> {
while (change.next()) {
if (change.wasAdded()) {
System.out.println("Éléments ajoutés : " + change.getAddedSubList());
}
if (change.wasRemoved()) {
System.out.println("Éléments supprimés : " + change.getRemoved());
}
if (change.wasReplaced()) {
System.out.println("Éléments remplacés");
}
}
});
// Maintenant, chaque fois que vous modifiez 'items',
// le listener sera appelé automatiquement
}
•
wasAdded() : Des éléments ont été ajoutés•
wasRemoved() : Des éléments ont été supprimés•
wasReplaced() : Des éléments ont été remplacés•
wasPermutated() : L'ordre des éléments a changé•
getAddedSubList() : Récupère les éléments ajoutés•
getRemoved() : Récupère les éléments supprimés
📝 Méthodes utiles d'ObservableList
ObservableList hérite de toutes les méthodes de List, plus quelques méthodes supplémentaires :
Méthodes principales
ObservableList<String> items = FXCollections.observableArrayList();
// Méthodes de List (héritées)
items.add("Élément"); // Ajouter un élément
items.add(0, "Premier"); // Ajouter à un index spécifique
items.remove("Élément"); // Supprimer un élément
items.remove(0); // Supprimer Ă un index
items.clear(); // Vider la liste
items.size(); // Taille de la liste
items.get(0); // Récupérer un élément
items.contains("Élément"); // Vérifier si contient
items.isEmpty(); // Vérifier si vide
// Méthodes spécifiques à ObservableList
items.addListener(listener); // Ajouter un listener
items.removeListener(listener); // Supprimer un listener
// Méthodes utilitaires
items.setAll("A", "B", "C"); // Remplacer tout le contenu
items.addAll("D", "E", "F"); // Ajouter plusieurs éléments
items.removeAll("A", "B"); // Supprimer plusieurs éléments
items.retainAll("C", "D"); // Garder seulement certains éléments
📝 Exemple complet : Gestionnaire de tâches
Créons un exemple complet d'un gestionnaire de tâches utilisant ObservableList :
MainController.java
package application;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private ListView<String> listViewTaches;
@FXML
private TextField txtNouvelleTache;
@FXML
private Button btnAjouter;
@FXML
private Button btnSupprimer;
@FXML
private Label lblNombreTaches;
// ObservableList pour les tâches
private ObservableList<String> taches;
@FXML
private void initialize() {
// Créer l'ObservableList
taches = FXCollections.observableArrayList();
// Lier Ă la ListView
listViewTaches.setItems(taches);
// Écouter les changements pour mettre à jour le compteur
taches.addListener((javafx.collections.ListChangeListener.Change<? extends String> change) -> {
while (change.next()) {
// Mettre Ă jour le compteur automatiquement
lblNombreTaches.setText("Nombre de tâches : " + taches.size());
}
});
// Initialiser le compteur
lblNombreTaches.setText("Nombre de tâches : " + taches.size());
}
@FXML
private void ajouterTache() {
String nouvelleTache = txtNouvelleTache.getText().trim();
if (!nouvelleTache.isEmpty()) {
taches.add(nouvelleTache);
txtNouvelleTache.clear();
// Le compteur se met à jour automatiquement grâce au listener !
}
}
@FXML
private void supprimerTache() {
String tacheSelectionnee = listViewTaches.getSelectionModel().getSelectedItem();
if (tacheSelectionnee != null) {
taches.remove(tacheSelectionnee);
// Le compteur se met Ă jour automatiquement !
}
}
@FXML
private void supprimerToutes() {
taches.clear();
// Le compteur se met Ă jour automatiquement !
}
}
• L'ObservableList est liée à la ListView avec
setItems()• Un listener met à jour automatiquement le compteur de tâches
• Toutes les modifications (ajout, suppression, clear) déclenchent automatiquement la mise à jour
• Pas besoin de code manuel pour synchroniser la vue avec les données
📝 ObservableList avec objets personnalisés
Vous pouvez utiliser ObservableList avec n'importe quel type d'objet, pas seulement des String :
Exemple : ObservableList de Personne
package application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
public class MainController {
@FXML
private ListView<Personne> listViewPersonnes;
// ObservableList d'objets Personne
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer l'ObservableList avec des Personnes
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 Ă la ListView
listViewPersonnes.setItems(personnes);
}
@FXML
private void ajouterPersonne() {
Personne nouvelle = new Personne("Nouveau", "Nom", 20, "nouveau@exemple.com");
personnes.add(nouvelle);
// La ListView se met Ă jour automatiquement !
}
@FXML
private void modifierPersonne() {
Personne selectionnee = listViewPersonnes.getSelectionModel().getSelectedItem();
if (selectionnee != null) {
// Modifier l'objet
selectionnee.setNom("Nom modifié");
// Pour que la ListView détecte le changement dans l'objet,
// il faut utiliser refresh() ou une ObservableList avec extractor
listViewPersonnes.refresh();
}
}
}
•
ObservableList détecte les ajouts/suppressions automatiquement• Mais si vous modifiez les propriétés d'un objet dans la liste, la ListView ne se met pas à jour automatiquement
• Dans ce cas, utilisez
listView.refresh() ou créez une ObservableList avec un extractor (voir section suivante)
💡 Points clés à retenir
- ObservableList : Liste qui notifie automatiquement les changements
- FXCollections.observableArrayList() : Méthode pour créer une ObservableList
- setItems() : Lie une ObservableList Ă un composant JavaFX (ListView, TableView, etc.)
- Mise Ă jour automatique : Les composants se mettent Ă jour quand la liste change
- addListener() : Pour écouter les changements dans la liste
- Méthodes héritées : Toutes les méthodes de List sont disponibles (add, remove, clear, etc.)
- Types personnalisés : Fonctionne avec n'importe quel type d'objet
ObservableList au lieu de List quand vous travaillez avec des composants JavaFX. C'est la différence entre une interface qui se met à jour automatiquement et une interface qui nécessite des appels manuels à refresh() !
6.1.2 – Ajout / suppression / mise à jour
Cette section détaille les différentes méthodes pour manipuler une ObservableList : ajouter, supprimer et mettre à jour des éléments. Vous découvrirez les différentes approches selon vos besoins et les bonnes pratiques pour chaque opération.
📝 Ajouter des éléments
Il existe plusieurs façons d'ajouter des éléments à une ObservableList :
Méthode 1 : Ajouter un élément (add)
ObservableList<String> items = FXCollections.observableArrayList();
// Ajouter un élément à la fin
items.add("Nouvel élément");
// Ajouter à un index spécifique
items.add(0, "Premier élément"); // Ajoute au début
items.add(2, "Élément à l'index 2");
Méthode 2 : Ajouter plusieurs éléments (addAll)
// Ajouter plusieurs éléments à la fin
items.addAll("Élément 1", "Élément 2", "Élément 3");
// Ajouter plusieurs éléments à un index spécifique
items.addAll(0, "A", "B", "C"); // Ajoute A, B, C au début
// Ajouter depuis une autre collection
List<String> autresElements = Arrays.asList("X", "Y", "Z");
items.addAll(autresElements);
Méthode 3 : Remplacer tout le contenu (setAll)
// Remplacer tout le contenu de la liste
items.setAll("Nouveau 1", "Nouveau 2", "Nouveau 3");
// Cela déclenche un changement "replaced" dans le listener
// Utile pour réinitialiser complètement la liste
•
add() : Pour ajouter un élément à la fois•
addAll() : Pour ajouter plusieurs éléments en une seule opération (plus efficace)•
setAll() : Pour remplacer complètement le contenu (réinitialisation)
📝 Supprimer des éléments
Méthode 1 : Supprimer un élément spécifique (remove)
// Supprimer par valeur
items.remove("Élément à supprimer");
// Supprimer par index
items.remove(0); // Supprime le premier élément
// Supprimer le dernier élément
items.remove(items.size() - 1);
Méthode 2 : Supprimer plusieurs éléments (removeAll)
// Supprimer plusieurs éléments spécifiques
items.removeAll("Élément 1", "Élément 2", "Élément 3");
// Supprimer depuis une autre collection
List<String> aSupprimer = Arrays.asList("X", "Y");
items.removeAll(aSupprimer);
Méthode 3 : Vider complètement (clear)
// Vider toute la liste
items.clear();
// Utile pour réinitialiser ou nettoyer
Méthode 4 : Supprimer conditionnellement (removeIf)
// Supprimer tous les éléments qui correspondent à une condition
items.removeIf(element -> element.length() < 5); // Supprime les éléments de moins de 5 caractères
// Exemple avec objets personnalisés
ObservableList<Personne> personnes = FXCollections.observableArrayList();
personnes.removeIf(p -> p.getAge() < 18); // Supprime les mineurs
Méthode 5 : Garder seulement certains éléments (retainAll)
// Garder seulement les éléments spécifiés
items.retainAll("Élément 1", "Élément 2"); // Garde seulement ces deux éléments
// Tous les autres éléments sont supprimés
•
removeAll() avec plusieurs éléments est plus efficace que plusieurs appels à remove()•
removeIf() est optimisé pour les suppressions conditionnelles• Utilisez
clear() plutôt que removeAll() pour vider complètement
📝 Mettre à jour des éléments
Méthode 1 : Remplacer un élément (set)
// Remplacer un élément à un index spécifique
items.set(0, "Nouveau premier élément");
// Cela déclenche un changement "replaced" dans le listener
Méthode 2 : Modifier les propriétés d'un objet
Si vous modifiez les propriétés d'un objet dans la liste, la ListView ne se met pas à jour automatiquement. Vous devez utiliser refresh() :
ObservableList<Personne> personnes = FXCollections.observableArrayList();
ListView<Personne> listView = new ListView<>();
listView.setItems(personnes);
// Modifier une propriété d'un objet
Personne personne = personnes.get(0);
personne.setNom("Nouveau nom");
// La ListView ne se met pas Ă jour automatiquement !
// Il faut appeler refresh()
listView.refresh();
// Ou utiliser un extractor (voir section 6.1.3)
Méthode 3 : Remplacer tous les éléments (replaceAll)
// Remplacer tous les éléments selon une transformation
items.replaceAll(element -> element.toUpperCase()); // Met tout en majuscules
// Exemple avec objets
personnes.replaceAll(p -> {
p.setAge(p.getAge() + 1); // Augmente l'âge de tous
return p;
});
📝 Opérations en lot (batch operations)
Pour effectuer plusieurs modifications sans déclencher plusieurs notifications, vous pouvez utiliser des opérations en lot :
// Méthode 1 : Utiliser beginChange() et endChange()
items.beginChange();
try {
items.add("Élément 1");
items.add("Élément 2");
items.remove("Ancien élément");
// Toutes ces opérations sont groupées en une seule notification
} finally {
items.endChange();
}
// Méthode 2 : Utiliser setAll() pour remplacer tout
// Plus simple et plus efficace pour un remplacement complet
items.setAll("Nouveau 1", "Nouveau 2", "Nouveau 3");
setAll() plutôt que clear() suivi de addAll() pour remplacer tout le contenu. C'est plus efficace et déclenche une seule notification.
📝 Exemple complet : Gestion avancée d'une liste
package application;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class MainController {
@FXML
private ListView<String> listViewItems;
@FXML
private TextField txtRecherche;
private ObservableList<String> items;
private ObservableList<String> itemsComplets; // Liste complète pour la recherche
@FXML
private void initialize() {
// Liste complète
itemsComplets = FXCollections.observableArrayList(
"Pomme", "Banane", "Orange", "Fraise", "Cerise", "Kiwi"
);
// Liste filtrée (affichée dans la ListView)
items = FXCollections.observableArrayList(itemsComplets);
listViewItems.setItems(items);
}
@FXML
private void ajouterItem() {
String nouvelItem = txtNouvelItem.getText().trim();
if (!nouvelItem.isEmpty()) {
// Ajouter à la liste complète
itemsComplets.add(nouvelItem);
// Si l'élément correspond au filtre, l'ajouter aussi à la liste affichée
if (txtRecherche.getText().trim().isEmpty() ||
nouvelItem.toLowerCase().contains(txtRecherche.getText().toLowerCase())) {
items.add(nouvelItem);
}
}
}
@FXML
private void supprimerItem() {
String selectionne = listViewItems.getSelectionModel().getSelectedItem();
if (selectionne != null) {
// Supprimer des deux listes
items.remove(selectionne);
itemsComplets.remove(selectionne);
}
}
@FXML
private void filtrer() {
String recherche = txtRecherche.getText().toLowerCase().trim();
if (recherche.isEmpty()) {
// Afficher tous les éléments
items.setAll(itemsComplets);
} else {
// Filtrer selon le critère
items.setAll(
itemsComplets.stream()
.filter(item -> item.toLowerCase().contains(recherche))
.collect(java.util.stream.Collectors.toList())
);
}
}
@FXML
private void trier() {
// Trier la liste
FXCollections.sort(items);
}
@FXML
private void supprimerDoublons() {
// Créer une nouvelle liste sans doublons
items.setAll(items.stream().distinct().collect(java.util.stream.Collectors.toList()));
}
}
💡 Points clés à retenir
- add() / addAll() : Pour ajouter des éléments
- remove() / removeAll() / removeIf() : Pour supprimer des éléments
- set() : Pour remplacer un élément à un index
- setAll() : Pour remplacer tout le contenu (plus efficace que clear + addAll)
- clear() : Pour vider complètement la liste
- refresh() : Nécessaire si vous modifiez les propriétés d'objets dans la liste
- Opérations en lot : Utilisez beginChange()/endChange() pour grouper les modifications
- âś… Utilisez
addAll()plutôt que plusieursadd()pour ajouter plusieurs éléments - ✅ Utilisez
setAll()plutĂ´t queclear()+addAll()pour remplacer - âś… Appelez
listView.refresh()après avoir modifié les propriétés d'objets - ✅ Utilisez
removeIf()pour les suppressions conditionnelles
6.1.3 – Binding liste ↔ vue
Le binding (liaison) permet de créer des connexions automatiques entre les données et l'interface utilisateur. JavaFX offre plusieurs mécanismes de binding pour synchroniser les ObservableList avec les composants de l'interface, y compris la détection des changements dans les propriétés des objets.
🎯 Types de binding
Il existe deux types principaux de binding :
- Binding unidirectionnel : Les données → Vue (les changements dans la liste mettent à jour la vue)
- Binding bidirectionnel : Les données ↔ Vue (les changements dans la liste ou la vue se synchronisent)
📝 Binding unidirectionnel (liste → vue)
Le binding unidirectionnel est le plus courant. Il est automatique quand vous utilisez setItems() :
ObservableList<String> items = FXCollections.observableArrayList();
ListView<String> listView = new ListView<>();
// Binding unidirectionnel : items → listView
listView.setItems(items);
// Maintenant, toute modification de 'items' met Ă jour automatiquement 'listView'
items.add("Nouvel élément"); // La ListView se met à jour automatiquement
items.remove(0); // La ListView se met Ă jour automatiquement
items.clear(); // La ListView se met Ă jour automatiquement
setItems() est automatique et ne nécessite aucune configuration supplémentaire. C'est la méthode la plus simple et la plus utilisée.
📝 Détecter les changements dans les objets (Extractor)
Par défaut, ObservableList détecte seulement les ajouts/suppressions d'éléments, pas les modifications des propriétés des objets. Pour détecter les changements dans les propriétés des objets, vous devez utiliser un extractor :
Exemple : ObservableList avec extractor
package application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.beans.value.ObservableValue;
import javafx.util.Callback;
public class MainController {
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer une ObservableList avec un extractor
// L'extractor indique quelles propriétés observer
personnes = FXCollections.observableArrayList(new Callback<Personne, ObservableValue[]>() {
@Override
public ObservableValue[] call(Personne personne) {
// Retourner les propriétés à observer
return new ObservableValue[] {
personne.nomProperty(), // Observer le nom
personne.prenomProperty(), // Observer le prénom
personne.ageProperty() // Observer l'âge
};
}
});
// Version lambda (plus simple)
personnes = FXCollections.observableArrayList(personne -> new ObservableValue[] {
personne.nomProperty(),
personne.prenomProperty(),
personne.ageProperty()
});
listViewPersonnes.setItems(personnes);
}
}
Classe Personne avec propriétés observables
Pour que l'extractor fonctionne, votre classe doit utiliser des propriétés observables JavaFX :
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();
// Constructeur
public Personne(String nom, String prenom, int age) {
this.nom.set(nom);
this.prenom.set(prenom);
this.age.set(age);
}
// Getters pour les propriétés (nécessaires pour l'extractor)
public StringProperty nomProperty() { return nom; }
public StringProperty prenomProperty() { return prenom; }
public IntegerProperty ageProperty() { return age; }
// Getters classiques
public String getNom() { return nom.get(); }
public String getPrenom() { return prenom.get(); }
public int getAge() { return age.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); }
}
• Quand vous modifiez une propriété d'un objet dans la liste, la ListView se met à jour automatiquement
• Plus besoin d'appeler
refresh() manuellement• La détection est automatique et efficace
📝 Binding avec plusieurs vues
Vous pouvez lier la mĂŞme ObservableList Ă plusieurs composants :
ObservableList<String> items = FXCollections.observableArrayList("A", "B", "C");
ListView<String> listView1 = new ListView<>();
ListView<String> listView2 = new ListView<>();
ComboBox<String> comboBox = new ComboBox<>();
// Lier la mĂŞme liste Ă plusieurs composants
listView1.setItems(items);
listView2.setItems(items);
comboBox.setItems(items);
// Toute modification de 'items' met Ă jour les 3 composants automatiquement !
items.add("D"); // Les 3 composants se mettent Ă jour
📝 Binding bidirectionnel avec sélection
Pour créer un binding bidirectionnel entre la sélection de la ListView et une propriété, vous devez utiliser des listeners car selectedItemProperty() est en lecture seule (ReadOnlyObjectProperty) :
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class MainController {
private ObjectProperty<Personne> personneSelectionnee = new SimpleObjectProperty<>();
@FXML
private void initialize() {
listViewPersonnes.setItems(personnes);
// Note : selectedItemProperty() est ReadOnly, donc on utilise des listeners
// pour créer un binding bidirectionnel manuel
// ListView → Propriété : Quand la sélection change dans la ListView
listViewPersonnes.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
personneSelectionnee.set(newVal);
});
// Propriété → ListView : Quand la propriété change depuis le code
personneSelectionnee.addListener((obs, oldVal, newVal) -> {
if (newVal != null) {
listViewPersonnes.getSelectionModel().select(newVal);
} else {
listViewPersonnes.getSelectionModel().clearSelection();
}
});
// Maintenant, vous pouvez modifier la sélection depuis le code
personneSelectionnee.set(personnes.get(0)); // Sélectionne le premier élément
// Et écouter les changements de sélection
personneSelectionnee.addListener((obs, oldVal, newVal) -> {
System.out.println("Nouvelle sélection : " + newVal);
});
}
}
•
selectedItemProperty() (ListView) retourne un ReadOnlyObjectProperty• Vous ne pouvez pas utiliser
bindBidirectional() avec selectedItemProperty()• Utilisez des listeners pour créer un binding bidirectionnel manuel avec ListView
• Le ComboBox a un
valueProperty() qui peut utiliser bindBidirectional() directement
Exemple : Binding bidirectionnel avec ComboBox
Contrairement Ă ListView, le ComboBox permet d'utiliser bindBidirectional() directement :
// Avec ComboBox, vous pouvez utiliser bindBidirectional() directement
ObjectProperty<Personne> personneSelectionnee = new SimpleObjectProperty<>();
// Binding bidirectionnel direct avec ComboBox
comboBoxPersonnes.valueProperty()
.bindBidirectional(personneSelectionnee);
// Maintenant, les changements dans les deux sens sont synchronisés automatiquement
personneSelectionnee.set(personnes.get(0)); // Met Ă jour le ComboBox
comboBoxPersonnes.setValue(personnes.get(1)); // Met à jour la propriété
• ListView : Utilisez des listeners pour le binding bidirectionnel (selectedItemProperty est ReadOnly)
• ComboBox : Vous pouvez utiliser
bindBidirectional() directement (valueProperty n'est pas ReadOnly)
📝 Exemple complet : Application avec binding avancé
package application;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.beans.value.ObservableValue;
import javafx.util.Callback;
public class MainController {
@FXML
private ListView<Personne> listViewPersonnes;
@FXML
private TextField txtNom;
@FXML
private TextField txtPrenom;
@FXML
private TextField txtAge;
@FXML
private Label lblNombrePersonnes;
// ObservableList avec extractor pour détecter les changements dans les objets
private ObservableList<Personne> personnes;
@FXML
private void initialize() {
// Créer ObservableList avec extractor
personnes = FXCollections.observableArrayList(personne ->
new ObservableValue[] {
personne.nomProperty(),
personne.prenomProperty(),
personne.ageProperty()
}
);
// Ajouter des personnes initiales
personnes.addAll(
new Personne("Dupont", "Jean", 25),
new Personne("Martin", "Marie", 30)
);
// Lier Ă la ListView
listViewPersonnes.setItems(personnes);
// Binding : sélection → champs de texte
listViewPersonnes.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
if (newVal != null) {
txtNom.setText(newVal.getNom());
txtPrenom.setText(newVal.getPrenom());
txtAge.setText(String.valueOf(newVal.getAge()));
}
});
// Binding : taille de la liste → label
lblNombrePersonnes.textProperty().bind(
javafx.beans.binding.Bindings.size(personnes).asString("Nombre de personnes : %d")
);
// Maintenant :
// - Modifier une propriété d'une personne met à jour automatiquement la ListView
// - Sélectionner une personne met à jour les champs de texte
// - Ajouter/supprimer une personne met Ă jour le compteur automatiquement
}
@FXML
private void modifierPersonne() {
Personne selectionnee = listViewPersonnes.getSelectionModel().getSelectedItem();
if (selectionnee != null) {
// Modifier les propriétés
selectionnee.setNom(txtNom.getText());
selectionnee.setPrenom(txtPrenom.getText());
selectionnee.setAge(Integer.parseInt(txtAge.getText()));
// La ListView se met à jour automatiquement grâce à l'extractor !
// Pas besoin d'appeler refresh()
}
}
}
• Extractor : Détecte automatiquement les changements dans les propriétés des objets
• Binding de sélection : Synchronise la sélection avec les champs de formulaire
• Binding de taille : Met à jour automatiquement les compteurs
• Moins de code : Pas besoin de gérer manuellement les mises à jour
💡 Points clés à retenir
- setItems() : Crée un binding unidirectionnel automatique
- Extractor : Permet de détecter les changements dans les propriétés des objets
- Propriétés observables : Utilisez StringProperty, IntegerProperty, etc. dans vos classes
- Binding bidirectionnel : Utilisez des listeners pour ListView (selectedItemProperty est ReadOnly), ou
bindBidirectional()pour ComboBox (valueProperty) - Plusieurs vues : Une ObservableList peut être liée à plusieurs composants
- Binding de taille : Utilisez
Bindings.size()pour les compteurs automatiques
- ✅ Utilisez un extractor si vous modifiez souvent les propriétés des objets dans la liste
- ✅ Les propriétés observables (StringProperty, etc.) sont nécessaires pour l'extractor
- âś… Le binding unidirectionnel avec
setItems()est suffisant dans la plupart des cas - âś… Pour le binding bidirectionnel avec ListView, utilisez des listeners (selectedItemProperty est ReadOnly)
- âś… Pour ComboBox, vous pouvez utiliser
bindBidirectional()directement avec valueProperty()
setItems()). Ajoutez un extractor seulement si vous avez besoin de détecter les changements dans les propriétés des objets. C'est plus simple et plus performant !