IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants Java Discussion :

[JTable] DefaultTableModel et JTree


Sujet :

Composants Java

  1. #1
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut [JTable] DefaultTableModel et JTree
    Bonjour,

    Je dispose d'une fenêtre avec une JTree sur la gauche et d'une JTable sur la droite.
    Lorsque je clique sur un noeud, le contenu de la jtable change.
    Pour cela, j'ai étendu la classe DefaultTableModel et en fonction du noeud sur lequel j'ai cliqué, je charge les données à partir d'une base d'une donnée dans mon TableModel.

    Pour éviter d'effectuer à chaque fois des requêtes dans la base, je stocke les données correspondant aux différents noeuds dans une collection dans mon TableModel et puis je m'occupe de les afficher et je rafraîchis la JTable à l'aide de fireTableDataChanged.

    Pouvez-vous me dire s'il s'agit d'une bonne pratique ?

  2. #2
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par speedster
    Bonjour,

    Je dispose d'une fenêtre avec une JTree sur la gauche et d'une JTable sur la droite.
    Lorsque je clique sur un noeud, le contenu de la jtable change.
    Pour cela, j'ai étendu la classe DefaultTableModel et en fonction du noeud sur lequel j'ai cliqué, je charge les données à partir d'une base d'une donnée dans mon TableModel.

    Pour éviter d'effectuer à chaque fois des requêtes dans la base, je stocke les données correspondant aux différents noeuds dans une collection dans mon TableModel et puis je m'occupe de les afficher et je rafraîchis la JTable à l'aide de fireTableDataChanged.

    Pouvez-vous me dire s'il s'agit d'une bonne pratique ?
    Oui, si tu as bien fait attention aux threads...
    J'imagine que tu charges dans la base de données à partir d'un thread utilisateur, et il faut que tu fasses le fireTableDataChanged dans l'EDT...

    J'ai justement écrit il y a quelques jours un article sur les modèles, ça concerne plus les ListModel mais c'est valable pour TableModel également...
    http://rom.developpez.com/java-swingui-models.pdf

  3. #3
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Il s'agit d'un client lourd donc appli monothread.

    Je me demande par contre s'il n'est pas plus judicieux de faire une requête à chaque fois dans la base de données en utilisant le cache des requêtes avec Hibernate (moins de code dans le TableModel) mais là je sors du thème de ce forum.

  4. #4
    Membre chevronné Avatar de Claythest
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    558
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 558
    Par défaut
    Citation Envoyé par speedster
    Il s'agit d'un client lourd donc appli monothread.
    Justement non !

    Client lourd = multi thread

    http://rom.developpez.com/java-swingworker/

    Ensuite, les données de ta base de données peuvent elles etres modifiée en dehors de ton programme JAVA ?

    Si non, alors il te suffit de stocker le résultat de chaque requetes, et de charger depuis la BD uniquement quand on t'en demande une nouvelle (avec peut être aussi gestion d'une taille limite / nombre de résultats de requêtes stockées pour ton cache).

    Si oui, alors c'est plus compliqué de gérer un cache, puisque tu sauras difficilement si ton cache est à jour ou non...

  5. #5
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Citation Envoyé par Claythest
    Justement non !

    Client lourd = multi thread

    http://rom.developpez.com/java-swingworker/
    Merci beaucoup pour cette précision. Je me retrouve bête là

    Le fireTableDataChanged est appelé dans la méthode qui fait appel à la requête.

    Dans ma classe qui étend le DefaultTableModel, j'ai une méthode que j'ai appelé setModel() dans laquelle je fais appel à ma requête puis le fireTableDataChanged.

    Je ne sais pas distinguer le thread utilisateur de l'edt

    Je gère un cache et j'utilise le pattern observateur. Les modifs ne sont faites que dans le programme. A ce moment, je lance un update qui fait à nouveau appel à la requête sinon il s'agit d'un simple affichage.

    Mais je me demandais s'il n'était pas plus judicieux de laisser hibernate gérer le cache à l'aide du cache de second niveau (cache des requêtes).


    Dans mon implémentation, la classe interne MatchCase représente le type d'objet mis en cache.

    Voici le code d'un de mes modèles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    public class MatchesTableModel extends GenericNonEditableTableModel implements
    		MatchUpdateListener, MatchInsertionListener {
     
    	/**
             * 
             */
    	private static final long serialVersionUID = -3466645481527750345L;
     
    	public static final int COLONNE_MATCH = 8;
     
    	private boolean displaying;
     
    	private InfosChampionnat infosChampionnat;
     
    	private Match sourceMatch;
     
    	private int typeClassementAffiche; // par défaut classement général
     
    	private boolean matchesParUtilisateur; // par défaut à faux
     
    	private boolean matchesJoues = true; // par défaut à vrai
     
    	private boolean matchesAJouer = true;  // par défaut à vrai
     
    	private UtilisateurParticipant uP;
     
    	private List<MatchCase> allDataVectors = new ArrayList<MatchCase>();
     
    	private class MatchCase {
    		private boolean toUpdate = false;
    		private InfosChampionnat infosChampionnat;
    		private List<Match> allMatches;
     
    		/**
                     * @param infosChampionnat
                     */
    		public MatchCase(InfosChampionnat infosChampionnat) {
    			super();
    			this.infosChampionnat = infosChampionnat;
    		}
     
    		public List<Match> getAllMatches() {
    			return allMatches;
    		}
     
    		public void setAllMatches(List<Match> allMatches) {
    			this.allMatches = allMatches;
    		}
     
    		public boolean isToUpdate() {
    			return toUpdate;
    		}
     
    		public void setToUpdate(boolean toUpdate) {
    			this.toUpdate = toUpdate;
    		}
     
    		@Override
    		public int hashCode() {
    			final int PRIME = 31;
    			int result = 1;
    			result = PRIME * result + ((infosChampionnat == null) ? 0 : infosChampionnat.hashCode());
    			return result;
    		}
     
    		@Override
    		public boolean equals(Object obj) {
    			if (this == obj)
    				return true;
    			if (obj == null)
    				return false;
    			if (getClass() != obj.getClass())
    				return false;
    			final MatchCase other = (MatchCase) obj;
    			if (infosChampionnat == null) {
    				if (other.infosChampionnat != null)
    					return false;
    			} else if (!infosChampionnat.equals(other.infosChampionnat))
    				return false;
    			return true;
    		}
    	}
     
    	/**
             * 
             */
    	public MatchesTableModel() {
    		setColumnIdentifiers();
    	}
     
    	@SuppressWarnings("unchecked")
    	private void setColumnIdentifiers() {
    		columnIdentifiers.add("");
    		columnIdentifiers.add("Journée");
    		columnIdentifiers.add("Domicile");
    		columnIdentifiers.add("");
    		columnIdentifiers.add("Vs.");
    		columnIdentifiers.add("");
    		columnIdentifiers.add("Extérieur");
    		columnIdentifiers.add("");
    	}
     
    	private Vector toVector(Match match) {
    		Vector<Object> ligne = new Vector<Object>();
    		ligne.addElement(match.getForfait());
    		ligne.addElement(match.getJournee());
    		ligne.addElement(match.getHomeUser());
    		ligne.addElement(match.getNbButs1());
    		ligne.addElement("-");
    		ligne.addElement(match.getNbButs2());
    		ligne.addElement(match.getAwayUser());
    		ligne.addElement(match.getVerrouille());
    		ligne.addElement(match);
    		return ligne;
    	}
     
    	@SuppressWarnings("unchecked")
    	private Vector filterMatches(List<Match> allMatches) {
     
    		Vector newDataVector = new Vector();
     
    		for (Match match : allMatches) {
    			// filtrer matches à jouer
    			if (!matchesJoues && matchesAJouer) {
    				if (match.getNbButs1() == null && match.getNbButs2() == null);
    				else continue;
    			}
    			// filtrer matches joués
    			else if (matchesJoues && !matchesAJouer) {
    				if (match.getNbButs1() != null && match.getNbButs2() != null);
    				else continue;
    			}
    			// matches joués et à jouer : pas de filtre
     
    			// filtre matches par utilisateur
    			if (matchesParUtilisateur) {
    				if (match.getUtilisateurParticipantByNumUtilisateurParticipant1().equals(uP)
    					|| match.getUtilisateurParticipantByNumUtilisateurParticipant2().equals(uP)) {
     
    					// classement général : pas de filtre
     
    					// classement à domicile
    					if (typeClassementAffiche == PescorerConstants.TYPE_CLASSEMENT_DOMICILE) {
    						if (match.getUtilisateurParticipantByNumUtilisateurParticipant1().equals(uP));
    						else continue;
    					}
    					// classement à l'extérieur
    					else if (typeClassementAffiche == PescorerConstants.TYPE_CLASSEMENT_EXTERIEUR) {
    						if (match.getUtilisateurParticipantByNumUtilisateurParticipant2().equals(uP));
    						else continue;
    					}
    				}
    				else continue;
    			}	
    			// matches de tous les utilisateurs : pas de filtre
     
    			// ajout du match
    			newDataVector.addElement(toVector(match));
    		}
    		return newDataVector;
    	}
     
    	private List<Match> loadAllMatches() {
    		MatchService matchService = (MatchService) PescorerApplicationContext.getInstance().getBean("matchService");
    		List<Match> allMatches = matchService.findMatchesByInfosChampionnat(infosChampionnat);
     
    		dataVector = filterMatches(allMatches);
     
    		fireTableDataChanged();
     
    		return allMatches;
    	}
     
    	private void setModel() {
    		MatchCase mCase = new MatchCase(infosChampionnat);
    		int idx = allDataVectors.indexOf(mCase);
    		if (idx != -1) {
    			MatchCase realMCase = allDataVectors.get(idx);
    			List<Match> allMatches = realMCase.getAllMatches();
    			if (allMatches != null) {
    				dataVector = filterMatches(allMatches);
    				fireTableDataChanged();
    			}
    			else {
    				realMCase.setAllMatches(loadAllMatches());
    				realMCase.setToUpdate(false);
    			}
    		}
    		else {
    			mCase.setAllMatches(loadAllMatches());
    			allDataVectors.add(mCase);
    			mCase.setToUpdate(false);
    		}
    	}
     
    	private void setModelUpdated() {
    		MatchCase mCase = new MatchCase(infosChampionnat);
    		int idx = allDataVectors.indexOf(mCase);
     
    		MatchCase realMCase = allDataVectors.get(idx);
    		realMCase.setAllMatches(loadAllMatches());
     
    		realMCase.setToUpdate(false);
    	}
     
    	public boolean isToUpdate() {
    		MatchCase mCase = new MatchCase(infosChampionnat);
    		int idx = allDataVectors.indexOf(mCase);
     
    		MatchCase realMCase = allDataVectors.get(idx);
    		return realMCase.isToUpdate();
    	}
     
    	public void setSource(Match match) {
    		this.sourceMatch = match;
    	}
     
    	public void setToUpdate(boolean toUpdate) {
    		InfosChampionnat infos = new InfosChampionnat(sourceMatch.getTournoi(), sourceMatch.getGroupe());
    		MatchCase mCase = new MatchCase(infos);
    		int idx = allDataVectors.indexOf(mCase);
    		// déjà existant
    		if (idx != -1) {
    			MatchCase realMCase = allDataVectors.get(idx);
    			realMCase.setToUpdate(toUpdate);
    		}
    		// n'existe pas encore
    		else {
    			mCase.setToUpdate(toUpdate);
    			allDataVectors.add(mCase);
    		}
    		this.infosChampionnat = infos;
    	}
     
    	public void update() {
    		if (isToUpdate()) {
    			setModelUpdated();
    		}
    	}
     
    	public void setModel(InfosChampionnat infosChampionnat, int selectedIndex, 
    			boolean matchesParUtilisateur, boolean matchesJoues, boolean matchesAJouer, UtilisateurParticipant uP) {
    		this.infosChampionnat = infosChampionnat;
    		this.setSelections(selectedIndex, matchesParUtilisateur, matchesJoues, matchesAJouer, uP);
    	}
     
    	public void setSelections(int selectedIndex, boolean matchesParUtilisateur, 
    			boolean matchesJoues, boolean matchesAJouer, UtilisateurParticipant uP) {
    		this.typeClassementAffiche = selectedIndex;
    		this.matchesParUtilisateur = matchesParUtilisateur;
    		this.matchesJoues = matchesJoues;
    		this.matchesAJouer = matchesAJouer;
    		this.uP = uP;
    		setModel();
    	}
     
    	public void setInfosChampionnat(InfosChampionnat infosChampionnat) {
    		this.infosChampionnat = infosChampionnat;
    	}
     
    	public void insert() {
    		MatchCase mCase = new MatchCase(infosChampionnat);
    		int idx = allDataVectors.indexOf(mCase);
     
    		if (idx != -1) {
    			MatchCase realMCase = allDataVectors.get(idx);
    			List<Match> allMatches = realMCase.getAllMatches();
     
    			if (allMatches != null) {
    				allMatches.add(sourceMatch);
     
    				if (displaying) {
    					dataVector = filterMatches(allMatches);
    					fireTableDataChanged();
    				}
    			}
    		}
    	}
     
    	public boolean isToInsert() {
    		return false;
    	}
     
    	public void setToInsert(boolean toInsert) {
    	}
     
    	public void setDisplaying(boolean displaying) {
    		this.displaying = displaying;
    	}
     
    }

  6. #6
    Membre chevronné Avatar de Claythest
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    558
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 558
    Par défaut
    Citation Envoyé par speedster
    Je ne sais pas distinguer le thread utilisateur de l'edt
    Ben en fait, tu n'es dans le thread utilisateur que dans le main, puis comme normalement tu invoques un setVisible sur une JFrame, tu passes dans l'EDT...

    Comme tous les évènements sont générés par l'EDT, si tu ne sors pas explicitement du thread courant, tout ton code s'exécutera en fait dans l'EDT... Cependant, pour des raisons de performances, il vaut mieux en sortir pour effectuer les calculs autre que ceux concernant directement l'IHM (classe SwingWorker)... et il te faut donc y "re-entrer" lorsque tu souhaites modifier des éléments de l'IHM... Bref, tu te retrouves dans un programme multi thread...

    En ce qui concerne le cache, pour savoir s'il est assez efficace ou non, il faut faire des tests... Tu peux dans un premier temps ne pas gérer de cache, laisser celui de hibernate. Si malgrès tout, tu as des temps de réponses trop lent, tu peux développer ton propre système de cache

  7. #7
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Alors ce n'est pas très bon de faire appel à ma requête dans mon TableModel ?

    Dans un cas, je fais appel à une requête, je fais des calculs dessus puis j'ajoute l'ensemble de résultats dans mon TableModel, mais tout est fait à l'intérieur de ma classe implémentant mon TableModel.

    De même, lorsque je valide certaines infos, en pressant un JButton, un appel est fait à la BD afin d'y insérer ces nouvelles données.

    Cette implémentation ne me semble donc pas correcte d'après ce que tu me dis ?

  8. #8
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par speedster
    Cette implémentation ne me semble donc pas correcte d'après ce que tu me dis ?
    Le problème c'est qu'un accès à une base de données est potentiellement long et pendant ce temps ton interface est figée...

  9. #9
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Citation Envoyé par ®om
    Le problème c'est qu'un accès à une base de données est potentiellement long et pendant ce temps ton interface est figée...
    Je comprends. Mais si je fais mon traitement dans un thread utilisateur, alors je verrais ma JTable sans données, tant que je n'aurais pas récupéré le résultat de ma requête ?

  10. #10
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par speedster
    Je comprends. Mais si je fais mon traitement dans un thread utilisateur, alors je verrais ma JTable sans données, tant que je n'aurais pas récupéré le résultat de ma requête ?
    Oui tout à fait, mais même si tu le fais dans l'EDT, tant que tu n'as pas récupéré le résultat de ta requête, tu ne peux pas les afficher non plus...
    La différence, c'est que si c'est dans l'EDT, ça fige toute ton interface...

  11. #11
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Citation Envoyé par ®om
    Oui tout à fait, mais même si tu le fais dans l'EDT, tant que tu n'as pas récupéré le résultat de ta requête, tu ne peux pas les afficher non plus...
    La différence, c'est que si c'est dans l'EDT, ça fige toute ton interface...
    D'après ton document sur la classe SwingWorker, je devrais redefenir la méthode doInBackground() dans laquelle je ferais appel à ma requête et done() dans laquelle j'appellerais fireTableDataChanged.

    Mais cette solution semble différente de ce que tu proposes dans ton document sur les modèles (utilisation de invokeLater()).

    D'autre part, pour informer mon modèle de la JTable d'afficher les données correspondant au noeud de la JTree, je transmets dans la méthode valueChanged(TreeSelectionEvent) du TreeSelectionListener des informations sur le noeud à mon TableModel et j'appelle la méthode setModel (que j'ai implémenté) de mon TableModel qui se chargera d'afficher ou de charger à partir de la base et d'afficher ensuite les données.

    Est-ce que cette solution est bonne ou est-ce plutôt de la bidouille ?

  12. #12
    Membre chevronné Avatar de Claythest
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    558
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 558
    Par défaut
    Citation Envoyé par speedster
    D'après ton document sur la classe SwingWorker, je devrais redefenir la méthode doInBackground() dans laquelle je ferais appel à ma requête et done() dans laquelle j'appellerais fireTableDataChanged.

    Mais cette solution semble différente de ce que tu proposes dans ton document sur les modèles (utilisation de invokeLater()).
    Bon, je ne connais pas ton appli, donc je vais prendre un exemple... Ca va peut etre correspondre à ton cas précisément...

    L'utilisateur va, via un bouton, raffaraichir les données d'une JTable. Pour ce faire, le actionPerformed du bouton va faire un SwingWorker qui va invoquer la méthode du TableModel demandant de se raffraichir. Cette méthode va exécuter la requete en BD, puis une fois le résultat récupéré, va signaler à la JTable qu'elle doit se mettre à jour en invoquant un invokeLater contenant le fireTableDataChanged.

    Ainsi, on sort de l'EDT dés connaissance de l'ordre de l'utilisateur (on sait ce qu'il veut faire, plus besoin de rester dans l'EDT), on effectue le calcul à l'extérieur de l'EDT (comme ça, l'interface continue à être opérationnelle, à réagir aux clics, aux animations...), une fois le calcul effectué, celui-ci demande à l'EDT d'exécuter le code de mise à jour.

    C'est plus clair comme ça ?

  13. #13
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Oui je te remercie.

    J'ai mis ce mécanisme en place avec la nouvelle classe SwingWorker de Java 6 en implémentant les méthodes doInBackground() et done().

    Peux-tu me dire si ma façon de faire est correct concernant ceci (je souhaite reproduire le fonctionnement d'un explorateur (comme Eclipse ou l'explorateur windows)) :
    D'autre part, pour informer mon modèle de la JTable d'afficher les données correspondant au noeud de la JTree, je transmets dans la méthode valueChanged(TreeSelectionEvent) du TreeSelectionListener des informations sur le noeud à mon TableModel et j'appelle la méthode setModel (que j'ai implémenté) de mon TableModel qui se chargera d'afficher ou de charger à partir de la base et d'afficher ensuite les données.

  14. #14
    Membre chevronné Avatar de Claythest
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    558
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 558
    Par défaut
    Je comprends pas pourquoi tu fais un appel à setModel...

    Normalement, setModel n'est appelé qu'une seule fois... Après, ton modèle quant à lui se met à jour soi via une méthode (setData par exemple) qui a son tour génère les évènements, soit le model est lui même listener d'autre chose, et il se met à jour tout en transmettant l'évènement de mise a jour...

  15. #15
    Membre confirmé
    Inscrit en
    Novembre 2003
    Messages
    142
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 142
    Par défaut
    Citation Envoyé par Claythest
    Je comprends pas pourquoi tu fais un appel à setModel...

    Normalement, setModel n'est appelé qu'une seule fois... Après, ton modèle quant à lui se met à jour soi via une méthode (setData par exemple) qui a son tour génère les évènements, soit le model est lui même listener d'autre chose, et il se met à jour tout en transmettant l'évènement de mise a jour...
    Le setModel() est une méthode que j'ai implémentée et non celle de l'API Java.
    Lorsqu'il y a un mouvement sur le JTree, je passe un objet de type InfosJournee qui contient des infos me permettant de compléter les parmètres de ma requête si le résultat de celle-ci n'est pas déjà en cache.
    C'est ce que fait la méthode setModel(). Tu peux regarder le code de la méthode setInfosJournee(InfosJournee) ci-dessous :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    /*
     * Created on 10 déc. 06
     *
     * 
     */
    package com.pescorer.ihm.model.table;
     
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Vector;
     
    import javax.swing.SwingWorker;
    import javax.swing.tree.DefaultMutableTreeNode;
    import javax.swing.tree.TreeModel;
     
    import com.pescorer.domain.model.Match;
    import com.pescorer.domain.model.data.InfosJournee;
    import com.pescorer.ihm.listener.MatchUpdateListener;
    import com.pescorer.ihm.model.tree.DuelTreeModel;
    import com.pescorer.service.MatchService;
    import com.pescorer.util.PescorerApplicationContext;
     
    /**
     * 
      * Classe : JourneeTableModel
     * 
     * Observeur immédiat
     *
     */
    public class JourneeTableModel extends GenericNonEditableTableModel implements MatchUpdateListener {
    	/**
             * 
             */
    	private static final long serialVersionUID = 1648719763875915253L;
     
    	private static final int COLONNE_FORFAIT = 0;
    	private static final int COLONNE_NBBUTS1 = 2;
    	private static final int COLONNE_NBBUTS2 = 4;
    	private static final int COLONNE_VERROUILLE = 6;
    	private static final int COLONNE_MATCH = 7;
     
    	private InfosJournee infosJournee;
     
    	private int rowSelected = -1;
     
    	private Match matchSelected;
     
    	private TreeModel explorerModel;
     
    	private List<JourneeCase> allDataVectors = new ArrayList<JourneeCase>();
     
    	private class JourneeCase {
    		private InfosJournee infosJournee;
    		private Vector dataVector;
     
    		public JourneeCase(InfosJournee infosJournee) {
    			this.infosJournee = infosJournee;
    		}
     
    		public Vector getDataVector() {
    			return dataVector;
    		}
     
    		public void setDataVector(Vector dataVector) {
    			this.dataVector = dataVector;
    		}
     
    		public InfosJournee getInfosJournee() {
    			return infosJournee;
    		}
     
    		@Override
    		public int hashCode() {
    			final int PRIME = 31;
    			int result = 1;
    			result = PRIME * result + ((infosJournee == null) ? 0 : infosJournee.hashCode());
    			return result;
    		}
     
    		@Override
    		public boolean equals(Object obj) {
    			if (this == obj)
    				return true;
    			if (obj == null)
    				return false;
    			if (getClass() != obj.getClass())
    				return false;
    			final JourneeCase other = (JourneeCase) obj;
    			if (infosJournee == null) {
    				if (other.infosJournee != null)
    					return false;
    			} else if (!infosJournee.equals(other.infosJournee))
    				return false;
    			return true;
    		}
    	}
     
    	private class JourneeWorker extends SwingWorker<Vector, Object> {
    		private JourneeCase jCase;
     
    		public JourneeWorker(JourneeCase jCase) {
    			this.jCase = jCase;
    		}
     
    		@SuppressWarnings("unchecked")
    		@Override
    		protected Vector doInBackground() throws Exception {
    			// récupération de la liste des matches de la journée en cours
    			MatchService matchService = (MatchService) PescorerApplicationContext.getInstance().getBean("matchService");
    			List<Match> matches = matchService.findMatchesByInfosJournee(infosJournee);
     
    			// noeud contenant la journée
    			DefaultMutableTreeNode nodeJournee = null;
    			if (explorerModel instanceof DuelTreeModel) {
    				nodeJournee = ((DuelTreeModel) explorerModel).getNodeJournee(infosJournee.getNumero());
    			}
    			// noeud auquel affecter la nouvelle instance de match
    			DefaultMutableTreeNode nodeMatch = null;
     
    			// ATTENTION ! Pour récupérer la Saison à jour avec les collections correspondantes, il faut la recharger à partir de la BD
    			for (Match match : matches) {
    				match.addMatchUpdateListener(JourneeTableModel.this);
    				// ajout de tous les autres modèles à la liste des observers
    				match.addMatchUpdateListeners(infosJournee.getTournoi().getSaison().getInternalFrame().getModels());
     
    				// retourne le noeud contenant le match
    				if (explorerModel instanceof DuelTreeModel) {
    					nodeMatch = ((DuelTreeModel) explorerModel).getNodeMatchFromNodeJournee(match, nodeJournee);
    				}
    				// affectation de la nouvelle instance de match au noeud
    				nodeMatch.setUserObject(match);
     
    				Vector<Object> ligne = new Vector<Object>();
    				ligne.addElement(match.getForfait());
    				ligne.addElement(match.getHomeUser());
    				ligne.addElement(match.getNbButs1());
    				ligne.addElement("-");
    				ligne.addElement(match.getNbButs2());
    				ligne.addElement(match.getAwayUser());
    				ligne.addElement(match.getVerrouille());
    				// objet correspondant attaché
    				ligne.addElement(match);
     
    				dataVector.addElement(ligne);
    			}
     
    			jCase.setDataVector(dataVector);
     
    			return dataVector;
    		}
     
    		@Override
    		protected void done() {
    			fireTableDataChanged();
    		}
     
    	}
     
    	public JourneeTableModel() {
    		setColumnIdentifiers();
    	}
     
    	@SuppressWarnings("unchecked")
    	private void setColumnIdentifiers() {
    		columnIdentifiers.add("");
    		columnIdentifiers.add("Domicile");
    		columnIdentifiers.add("");
    		columnIdentifiers.add("Vs.");
    		columnIdentifiers.add("");
    		columnIdentifiers.add("Extérieur");
    		columnIdentifiers.add("");
    	}
     
    	private void setModel() {
    		JourneeCase jCase = new JourneeCase(infosJournee);
    		int idx = allDataVectors.indexOf(jCase);
    		// le dataVector de infosJournee actuel existe déjà
    		if (idx != -1) {
    			dataVector = allDataVectors.get(idx).getDataVector();
    			fireTableDataChanged();
    		}
    		// le dataVector de infosJournee n'existe pas encore
    		else {
    			dataVector = new Vector();
    			fireTableDataChanged();
    			new JourneeWorker(jCase).execute();
    			allDataVectors.add(jCase);
    		}
    	}
     
    	/**
             * Retourne le match correspondant à la ligne sélectionnée.
             * @param row
             * @return l'objet match
             */
    	public Match getMatchSelectedRow(int row) {
    		rowSelected = row;
    		matchSelected = (Match) getValueAt(row, COLONNE_MATCH);
    		return matchSelected;
    	}
     
    	public void setSource(Match match) {
    	}
     
    	/* (non-Javadoc)
    	 * @see com.pescorer.util.ObserverInterface#isToUpdate()
    	 */
    	public boolean isToUpdate() {
    		return false;
    	}
     
    	/* (non-Javadoc)
    	 * @see com.pescorer.util.ObserverInterface#setToUpdate(boolean)
    	 */
    	public void setToUpdate(boolean toUpdate) {
    	}
     
    	@SuppressWarnings("unchecked")
    	public void update() {
    		setValueAt(matchSelected.getForfait(), rowSelected, COLONNE_FORFAIT);
    		setValueAt(matchSelected.getNbButs1(), rowSelected, COLONNE_NBBUTS1);
    		setValueAt(matchSelected.getNbButs2(), rowSelected, COLONNE_NBBUTS2);
    		setValueAt(matchSelected.getVerrouille(), rowSelected, COLONNE_VERROUILLE);
    	}
     
    	/* (non-Javadoc)
    	 * @see java.lang.Object#hashCode()
    	 */
    	@Override
    	public int hashCode() {
    		final int PRIME = 31;
    		int result = 1;
    		result = PRIME * result + ((infosJournee == null) ? 0 : infosJournee.hashCode());
    		return result;
    	}
     
    	/* (non-Javadoc)
    	 * @see java.lang.Object#equals(java.lang.Object)
    	 */
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		final JourneeTableModel other = (JourneeTableModel) obj;
    		if (infosJournee == null) {
    			if (other.infosJournee != null)
    				return false;
    		} else if (!infosJournee.equals(other.infosJournee))
    			return false;
    		return true;
    	}
     
    	/**
             * @param infosJournee the infosJournee to set
             */
    	public void setInfosJournee(InfosJournee infosJournee) {
    		this.infosJournee = infosJournee;
    		setModel();
    	}
     
    	/**
             * @param explorerModel the explorerModel to set
             */
    	public void setExplorerModel(TreeModel explorerModel) {
    		this.explorerModel = explorerModel;
    	}
     
    	/**
             * Retourne la ligne contenant le match donné 
             * (et ceci par rapport au dataVector courant).
             * @param match
             * @return
             */
    	public int getRow(Match match) {
    		int i=0;
    		for (Iterator it = dataVector.iterator(); it.hasNext();) {
    			Vector ligne = (Vector) it.next();
    			if (ligne.contains(match)) {
    				break;
    			}
    			i++;
    		}
    		return i;
    	}
     
    }
    Je pense que ma façon de faire n'est pas très propre mais comment dois-je informer mon TableModel de changer ses données en fonction du noeud choisi dans le JTree ?

  16. #16
    Membre chevronné Avatar de Claythest
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    558
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 558
    Par défaut
    Ben si c'est ça

    Ta méthode setInfosJournée sera invoquée suite à une action de l'utilisateur (genre un actionPerformed sur un bouton), qui va utiliser le SwingWorker pour invoquer cette méthode setInfosJournee

    Après, si tu as beaucoup d'actions différentes et que tu veux faire plus propre, il te suffit de centraliser dans une classe toutes les actions. Ainsi le actionPerformed invoque l'action correspondante, qui lui fait passer le "message" au table model etc... toujours en utlisant SwingWorker pour ne pas surcharger l'EDT une fois l'évènement capté

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème rafraichissement JTable/DefaultTableModel
    Par marc.L dans le forum Composants
    Réponses: 4
    Dernier message: 20/02/2015, 10h28
  2. Sérialisation JTable DefaultTableModel
    Par superstarz dans le forum Composants
    Réponses: 4
    Dernier message: 21/01/2013, 04h09
  3. Drag n drop JTable -> JTree
    Par KeKeMaN dans le forum Composants
    Réponses: 6
    Dernier message: 14/05/2007, 16h50
  4. mis a jour Jtree depuis JTable
    Par owen2 dans le forum Composants
    Réponses: 1
    Dernier message: 12/08/2006, 15h57
  5. [Jtable] DefaultTableModel renderer des boolean
    Par lilou77 dans le forum Composants
    Réponses: 2
    Dernier message: 20/12/2005, 16h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo