Voir directement le résumé-simplification
Une JTable aux dimensions modifiables dynamiquement et dont les cellules des rangées contiennent, dans quelques colonnes contigües, des objets non basiques (ici JRadioButton regroupés en rangées), cela devrait intéresser beaucoup de programmeurs en Java, il me semble.
Dans un premier SSCCE se trouve le code le plus concis possible d'une JTable dont toutes les cellules contiennent un bouton-radio et où un seul bouton-radio à la fois peut effectivement être sélectionné dans chaque rangée; pour me prouver qu'avec une JTable aux dimensions statiques, ça fonctionne. Voir ma propre réponse à ma question dans http://www.developpez.net/forums/d15...roupes-rangee/
Dans un deuxième SSCCE, je tente d'insérer dynamiquement quelques colonnes à JRadioButtons, entre deux colonnes aux données calculées : https://www.developpez.net/forums/d1...n/#post8898511
Mon problème : Les colonnes et rangées sont bien ajoutées, mais les boutons-radios de leurs cellules ne sont pas activables. Les séquences d'invocation de méthodes par les classes JTable, JTableModel, AbstractTableModel, JRadioButton font apparaître un malfonctionnement (Séquences des méthodes 'getRowCount', 'getColumnCount', 'getCellRenderer', 'prepapreRenderer', 'getValueAt', 'setValueAt', 'propertyChange', 'getTableCellRendererComponent', 'getTableCellEditorComponent', 'getCellEditorValue', 'actionPerformed', ...).
Apparamment, ce ne fut pas une bonne idée de tenter de découvrir d'où pourrait provenir l'erreur sur base du relevé des séquences de méthodes appelées, car je n'ai obtenu aucune réponse à ma question. Entretemps, le problème est resté le même.
Je profite de l'occasion pour demander au gérant de cette discussion placée à un mauvais endroit de bien vouloir la déplacer vers 'Interfaces graphiques > AWT Swing > Tables'.
Le SSCCE que j'envoie cette fois-ci est le plus compact possible, mais toutefois suffisant pour montrer la complexité d'insertion dynamique de colonnes de boutons-radios et de rangées, et se base sur les quatre fichiers sources (des mêmes classes TestTable (renomée ici 'XYExtensTable_SSCCE'), MonModTable, GestionnObjetsDUneRangée et MonObjet) identiquement à ceux de mon premier SSCCE.
J'utilise un modèle de données propre ('MonModTable') héritant de 'AbstractTableModel' (non de 'DefaultTableModel') et générant ...
- une List<GestionnObjetsDUneRangée> gestionnDonnéesTteLaTable (rangées). 'GestionnObjetsDUneRangée' elle-même n'est pas directement une List<Object> (colonnes), mais est une classe qui en contient une (List<Object> objetsDUneRangée).
- et une List<String> libellésColonnes.
À chaque ajout/retrait d'une colonne de boutons-radios, ces deux listes sont remises à jour par la méthode 'élaborTtsRangéesTable()'.
Important : Dans cette application,
- Une rangée est ajoutée chaque fois qu'une colonne (de boutons-radios) est ajoutée.
- Le modèle de la table est reconçu intégralement à chaque ajout/retrait d'une colonne (et d'une rangée) et la table entière est repeinte. Il n'est donc pas question d'insérer une seule rangée dans une table existante, de modifier le contenu d'une seule cellule, etc., tel qu'expliqué p. ex. dans http://michelangemfwamba.blogspot.be...dynamique.html
Le fonctionnement devrait être le suivant : À chaque actionnement du bouton-poussoir 'Ajout d'une colonne' (= boutAjoutUneColon dans 'XYExtensTable_SSCCE'), la méthode 'miseÀJourModèleEtStructTable(...)' (dans la classe 'XYExtensTable_SSCCE') est appelée, qui elle-même appelle, en premier lieu, 'élaborTtsRangéesTable()' (dans la classe 'MonModTable').
- 'élaborTtsRangéesTable()' est en charge ...
- - d'insérer le libellé de la nouvelle colonne (aux boutons-radios) ajoutée
- - de composer une série de valeurs décimales factices et de les disposer en ArrayList (dans 'objetsDUneRangée' dans 'GestionnObjetsDUneRangée'), rangée par rangée, dans les cellules autres que celles des boutons-radios.
- - de générer les boutons-radios ('monObjet') à disposer dans les places adéquates de l'ArrayList 'objetsDUneRangée'.
- - fireTableStructureChanged();
- 'miseÀJourModèleEtStructTable(...)' est en charge ...
- - de déplacer la colonne pour qu'elle devienne l'avant-dernière
Supposons, lors de l'ajout d'une colonne à boutons-radios, que les 'objetsDUneRangée' (dans 'GestionnObjetsDUneRangée') de chaque rangée reçoivent une nouvelle cellule (un booléen qui est rendu comme bouton-radio) et que 'libellésColonnes' se fait insérer un nouveau libellé. Il faut que la JTable réalise que son modèle a grandi en nombre de colonnes et en nombre de rangées. Je suppose que c'est le but même de 'fireTableStructureChanged();'.
Par exemple au re-dessinage de la table est générée une séquence d'appels de méthodes (getColumnCount(), getRowCount, setValueAt(), ... que j'ai "@Overridé" dans mon 'MonModTable').
Je suppose aussi que dans 'miseÀJourModèleEtStructTable(...)' (dans 'XYExtensTable_SSCCE') et juste après la mise à jour du modèle dans 'élaborTtsRangéesTable()', il ne faut plus ajouter de colonne, ni en bouger de place, ni quoi que ce soit d'autre.
Cette application à quatre classes ne fonctionne pas encore complètement :
- L'ajout dynamique de colonnes de boutons-radios fait apparaître des boutons-radios inertes. Ils n'inter-agissent plus par rangée; ils ne sont même plus sélectionnables.
- Les '0' de la dernière colonne (Z) sont remplacés par de boutons-radios (inertes).
- 'coloDeTable.setMaxWidth(40);' ne fonctionne plus, apparamment depuis l'implémentation de 'fireTableStructureChanged()' à la fin de 'élaborTtsRangéesTable()'.
... contrairement à ce qui se passe dans l'SSCCE de la table statique (1er URL de ci-dessus). Je pense cependant être près du bon fonctionnement complet.
Un féru en JTables dynamiques pourrait-il m'aider à trouver ce qui se passe, ce que j'omets, ce qui m'échappe, ... ? Merci d'avance d'essayer de m'aider.
Voici les quatre classes de mon SSCEE à copier :
- XYExtensTable_SSCCE (375 l.)- MonModTable (395 l.)
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374 /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates and open the template in the editor. * Short, Self Contained, Correct (Compilable), Example http://sscce.org/ * @author Chavadam */ package xyextenstable_sscce; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFrame; // import javax.swing.JPanel; // import javax.swing.JSeparator; import javax.swing.AbstractCellEditor; import javax.swing.JRadioButton; // import javax.swing.ButtonGroup; import javax.swing.JScrollPane; import javax.swing.JTable; // import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; // RenduCol3 import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; // import javax.swing.table.TableColumnModel; import javax.swing.JButton; import javax.swing.GroupLayout; // import javax.swing.LayoutStyle; // addPreferredGap( import javax.swing.SwingConstants; // CENTER import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; // main() import javax.swing.event.*; // TableModelListener, TableModelevent import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_AVANT; import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_APRES; /** * */ public class XYExtensTable_SSCCE extends JFrame implements ActionListener // TableModelListener { // <editor-fold defaultstate="collapsed" desc="Déclarations des variables"> private /* final */ JTable table; /* Local variables 'renduCellBoutRad' and 'monModTable' are accessed from * within a inner class (JTable) --> needs to be declared final. */ private /* final */ MonModTable monModTable; // private TableColumnModel modèColonTable; // Constructeur : La largeur des intitulés de chaque colonne private TableColumn coloDeTable; // et 'miseÀJourModèleEtStructTable()' private byte nbreColoTable; private static final byte LARGEUR_MAX_COL = 50; private int largTotTable; private int largTotTable_TtesRangées; private byte nbreColÀBP_AvantModif, nbreColÀBP; private JButton boutAjoutUneColon; private JButton boutRetraitUneColon; static final boolean DEBUG = false; // </editor-fold> protected void initUI() // public XYExtensTable_SSCCE() { // <editor-fold defaultstate="collapsed" desc="Initialisation des variables"> monModTable = new MonModTable(nbreColÀBP = 0, nbreColÀBP_AvantModif = 0); table = new JTable(monModTable) { DefaultTableCellRenderer renduCell; RendEdit_CellBoutRad rendu_CellBoutRad; // Bloc constructeur par défaut de la JTable. { // Méthode héritée de JLabel /* As we are calling 'super.getTableCellRendererComponent', we need to extend * 'DefaultTableCellRenderer'; not simply implement 'TableCellRenderer'. */ /* If you do not extend from 'DefaultTableCellRenderer', you will need to be * careful to find ways to indicate whether the cell has focus or not, is * editable or not, and is selected or not. If you don't, then those cells * won't match the appearance of other table cells. */ renduCell = new DefaultTableCellRenderer(); renduCell.setHorizontalAlignment(SwingConstants.CENTER); rendu_CellBoutRad = new RendEdit_CellBoutRad(); // setRowHeight(55); // Rendu inopérationnel par 'ajustageLargeurCol()'. // La largeur des intitulés de chaque colonne largTotTable = 0; // = (byte) table.getModel().getColumnCount(); nbreColoTable = (byte) monModTable.getColumnCount(); for (int col = 0; col < nbreColoTable; col++) { // Cette quinzaine de lignes rien que pour trouver la largeur des intitulés de chaque colonne ... coloDeTable = this.getColumnModel().getColumn(col); int largeurColPréfér = coloDeTable.getMinWidth(); // int largeurMaxCol = coloDeTable.getMaxWidth(); coloDeTable.setMaxWidth(LARGEUR_MAX_COL); TableCellRenderer renduDEntête = coloDeTable.getHeaderRenderer(); if (renduDEntête == null) renduDEntête = this.getTableHeader().getDefaultRenderer(); Object contenuDEntête = coloDeTable.getHeaderValue(); Component composDeRenduDEntête = renduDEntête.getTableCellRendererComponent( this, contenuDEntête, false, false, 0, col); // + table.getIntercellSpacing().width; Pourquoi ne va pas ? int largeurEntêteCol = composDeRenduDEntête.getPreferredSize().width + 12; // colonneDeTable.setPreferredWidth(largeurEntêteCol); largeurColPréfér = Math.max(largeurColPréfér, largeurEntêteCol); // Lors de la création du JFrame et de la JTable, aucune rangée n'est à afficher. */ largTotTable += largeurColPréfér; coloDeTable.setPreferredWidth(largeurColPréfér); // colonneDeTable.setWidth(largeurColPréfér); } // Fin de 'La largeur des intitulés de chaque colonne' /* Pour que les intitulés de colonnes soient affichés même lorsqu'il * n'y a aucune colonne à bouton-radio (dynamique). */ largTotTable_TtesRangées = Math.max(largTotTable_TtesRangées, largTotTable); } // Fin du bloc constructeur par défaut de la JTable. // Overrides method from javax.swing.JTable @Override public TableCellRenderer getCellRenderer(int rang, int col) { int nbreColo = monModTable.getColumnCount() - NBRE_FIXE_COL_APRES; if (col < NBRE_FIXE_COL_AVANT) return renduCell; else if (col >= NBRE_FIXE_COL_AVANT && col <= nbreColo) // col <= monModTable.idxColFinBoutRadio) return rendu_CellBoutRad; else // if (col > nbreColo) return renduCell; // CENTER } /* Prepares the renderer by querying the data model for the * value and selection state of the cell at row, column. * With Java, you can specify cell renderers and editors either by * column or by data type. */ @Override public Component prepareRenderer( TableCellRenderer renduCelluleTableÀPréparer, int rang, int col) { // La classe parente de 'JTable' est 'javax.swing.JComponent'. short wave10 = 0; // Rien que pour placer un breakpoint. À ôter. /* Pour toutes les cellules des colonnes ne contenant pas un objet de type 'MonObjet' : * - 'renduCelluleTableÀPréparer' contient un objet de type 'DefaultTableCellRenderer'. * - 'compos' contient un objet de type 'DefaultTableCellRenderer'. * Pour toutes les cellules des colonnes contenant bien un objet de type 'MonObjet' : * - 'renduCelluleTableÀPréparer' contient un objet de type 'RendEdit_CellBoutRad'. * - 'compos' contient un objet de type 'JRadioBouton'. */ /* Appel de 'getValueAt()' dans 'MonModTable' * et de 'isSélectionné()" dans 'MonObjet' */ final Component compos = super.prepareRenderer(renduCelluleTableÀPréparer, rang, col); // compos.setBackground(Color.GRAY); return compos; } // Nécessaire ? @Override public void tableChanged(TableModelEvent e) { // La classe parente de 'JTable' est 'javax.swing.JComponent'. super.tableChanged(e); repaint(); } }; // Fin de 'new JTable(...' // <editor-fold defaultstate="collapsed" desc="Largeur chaque colonne = minimum"> /* Anihile l'extension horizontale automatique de la table faisant en sorte qu'elle * occupe tout l'espace horizontal du panneau JTabbedPane qui la contient. */ table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); // table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); // table.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); // table.setPreferredScrollableViewportSize(new Dimension(620, 80)); // Width, height // table.setFillsViewportHeight(true); // Ne fonctionne pas. table.setFillsViewportHeight(true); table.setPreferredScrollableViewportSize(new Dimension( largTotTable_TtesRangées, // Width table_ChoixMach.getTableHeader().getWidth() 160) ); // Height table_ChoixMach.getHeight() = 10 rows * 16 pixels/row // table.getTableHeader().setToolTipText("Tool tip commun à toutes les colonnes"); // </editor-fold> // Fin de "Largeur chaque colonne = minimum" JScrollPane panDéroul_Table = new JScrollPane(table); // panDéroul_Table.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); // panDéroul_Table.setViewportView(table); // - - - - - - - - - - - boutAjoutUneColon = new JButton("Ajout d'une colonne"); boutAjoutUneColon.addActionListener(this); boutRetraitUneColon = new JButton("Retrait d'une colonne"); // boutRetraitUneColon.addActionListener(this); // - - - - - - - - - - - this.add(panDéroul_Table, BorderLayout.CENTER); this.add(boutAjoutUneColon, BorderLayout.NORTH); this.add(boutRetraitUneColon, BorderLayout.SOUTH); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } // Fin du constructeur de 'XYExtensTable_SSCCE' // </editor-fold> // Fin de 'Initialisation des variables' // Boutons-Poussoirs Ajout / retrait d'une colonne @Override public void actionPerformed(ActionEvent évé) { nbreColoTable = (byte) table.getColumnModel().getColumnCount(); nbreColÀBP = (byte) (nbreColoTable - (NBRE_FIXE_COL_AVANT + NBRE_FIXE_COL_APRES)); nbreColÀBP_AvantModif = nbreColÀBP; if (évé.getSource() == boutAjoutUneColon) { miseÀJourModèleEtStructTable(++nbreColÀBP, nbreColÀBP_AvantModif); boutRetraitUneColon.setEnabled(true); } else if (évé.getSource() == boutRetraitUneColon) { if (nbreColÀBP <= 0) boutRetraitUneColon.setEnabled(false); else { miseÀJourModèleEtStructTable(--nbreColÀBP, nbreColÀBP_AvantModif); boutRetraitUneColon.setEnabled(true); } } } /** Remet à jour les données de 'monModTable' * Note : table.getModel().addColumn(new TableColumn(libelléCol)); est seulement * fourni dans 'DefaultTableModel', pas prévu par 'AbstractTableModel'. * Cette méthode est appelée suite à l'actionnement des deux boutons-poussoirs. * @param nbreColÀBP3 * @param nbreColÀBP_AvantModif3 */ public void miseÀJourModèleEtStructTable(byte nbreColÀBP3, byte nbreColÀBP_AvantModif3) { byte nbreRangées = monModTable.élaborTtsRangéesTable(); // table.setModel(monModTable); // nbreColoTable = (byte) monModTable.libellésColonnes.size(); // 4 nbreColoTable = (byte) table.getColumnModel().getColumnCount(); // 3 // Pour ce SSCCE, ce n'est toujours qu'une seule colonne à la fois qui est à ajouter ou à retirer. byte nbreColÀAjouter = (byte) ((nbreColÀBP3 - nbreColÀBP_AvantModif3)); // Dernière colonne de radio-boutons après laquelle la prochaine sera à ajouter. byte idxDernColoBoutRad; if (nbreColÀAjouter > 0) { /* coloDeTable = new TableColumn(); coloDeTable.setMaxWidth(40); // Il faut des 'RendEdit_CellBoutRad' différents pour 'CellEditor' et 'CellRenderer'. // edit_CellBoutRad = new RendEdit_CellBoutRad(); coloDeTable.setCellEditor (new RendEdit_CellBoutRad()); coloDeTable.setCellRenderer(new RendEdit_CellBoutRad()); table.addColumn(coloDeTable); nbreColoTable++; // ou nbreColoTable = (byte) table.getColumnCount(); idxDernColoBoutRad = (byte) (nbreColoTable - NBRE_FIXE_COL_APRES -1); /* La nouvelle colonne est toujours ajoutée à l'extrême droite de la table et * est donc à déplacer à la première des NBRE_FIXE_COL_APRES dernières colonnes. * / table.moveColumn(nbreColoTable -1, idxDernColoBoutRad); // nbreColÀAjouter--; */ // Le groupage fonctionnel des radio-boutons est fait par 'GestionnObjetsDUneRangée'. } // fin de 'if (nbreColÀAjouter > 0)' else if (nbreColÀAjouter < 0) // nbreColÀAjout est négatif => Colonnes à ôter. { nbreColoTable = (byte) table.getColumnCount(); idxDernColoBoutRad = (byte) (nbreColoTable - NBRE_FIXE_COL_APRES -1); coloDeTable = table.getColumn(idxDernColoBoutRad); monModTable.libellésColonnes.remove((int) (NBRE_FIXE_COL_AVANT + nbreRangées)); table.removeColumn(coloDeTable); // Deselects the columns from index0 to index1, inclusive. // table.removeColumnSelectionInterval( // (int) NBRE_FIXE_COL_AVANT, (int)(NBRE_FIXE_COL_AVANT - nbreColÀAjouter)); } } /** * @param args the command line arguments * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException * @throws UnsupportedLookAndFeelException */ public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() // Implements method from java.lang.Runnable { new XYExtensTable_SSCCE().initUI(); } } ); } // - - - - - - - - - - - // Pas "extends JRadioButton". private class RendEdit_CellBoutRad extends AbstractCellEditor implements TableCellRenderer, TableCellEditor, ActionListener { private final JRadioButton boutonRadio; public RendEdit_CellBoutRad() { this.boutonRadio = new JRadioButton(); boutonRadio.addActionListener(this); // Leaking 'this' in constructor. boutonRadio.setHorizontalAlignment(SwingConstants.CENTER); boutonRadio.setOpaque(false); } /* Implements the unique method from 'javax.swing.table.TableCellRenderer' interface. * https://docs.oracle.com/javase/7/docs/api/index.html?javax/swing/table/TableCellRenderer.html * L'objet renvoyé par 'getValueAt()' dans 'MonModTable' est traité ici. */ @Override public Component getTableCellRendererComponent(JTable table, Object valeur, boolean estSélectionné, boolean aLeFocus, int rangée, int colonne) { boutonRadio.setSelected(Boolean.TRUE.equals(valeur)); boutonRadio.setOpaque(true); // boutonRadio.setBackground(java.awt.Color.yellow); return boutonRadio; } // This method is called when a cell value is edited by the user. // Implements method from 'javax.swing.table.TableCellEditor'. @Override public Component getTableCellEditorComponent(JTable table, Object valeur, boolean estSélectionné, int rangée, int colonne) { boutonRadio.setSelected(Boolean.TRUE.equals(valeur)); return boutonRadio; } // Implements method from 'java.awt.event.ActionListener'. @Override public void actionPerformed(ActionEvent e) { stopCellEditing(); } // Implements method from 'javax.swing.CellEditor'. JTable or JTree @Override public Object getCellEditorValue() { // 'isSelected()' is inherited from class javax.swing.AbstractButton . return boutonRadio.isSelected(); // boolean } /* @Override public void setBackground(Color bg) { ; } */ } }- GestionnObjetsDUneRangée (128 l.)
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 /* * @author Chavadam */ package xyextenstable_sscce; import java.math.BigDecimal; import java.util.List; // Interface import java.util.ArrayList; // import java.util.Comparator; // import java.util.Collections; // import static java.util.Collections.sort; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.table.AbstractTableModel; // import static xyextenstable_sscce.XYExtensTable_SSCCE.DEBUG; /** * Swing ne prévoit pas la possibilité d'implémenter un "Listener" (= "guêteur") * cellule par cellule --> en implémenter un à 'class XYExtensTable_SSCCE'. */ class MonModTable extends AbstractTableModel implements PropertyChangeListener { // <editor-fold defaultstate="collapsed" desc="Déclaration des variables"> private List<BigDecimal> échelleValeurs1eColonne; private byte nbreColÀBP2; private byte nbreColÀBP_AvantModif2; // Horizontalement // Not 'private' because capability to remove items from XYExtenTable_SSCCE. List<String> libellésColonnes; // private Byte libelléDernièreColonne; public List<String> libelAutresColQueColÀBP; // Formats des contenus des colonnes : String, RendeurEditeur_CelluleBoutonRadio, BigDecimal public final List<String> renduCellCol; /* 'idxRangée' dans 'Composer la base des rangées de données de la table' dans * 'élaborTtsRangéesTable()' doit être accessible dans '@Override propertyChange(evt)'. */ private byte idxRangée; // private BigDecimal[] énElecTherm_DuréeFonct; // Avant et après le groupe d'un nombre variable de colonnes à radio-boutons. static final byte NBRE_FIXE_COL_AVANT = 2; static final byte NBRE_FIXE_COL_APRES = 1; // private int colCommencementBoutRadio = NBRE_FIXE_COL_AVANT; int idxColFinBoutRadio = 0; // Contient et gère les rangées de boutons-radios et leurs regroupements. private List<GestionnObjetsDUneRangée> gestionnDonnéesTteLaTable; private GestionnObjetsDUneRangée gestionObjDUneRang; // </editor-fold> // Fin de 'Déclaration des variables' MonModTable(byte nbreColÀBP1, byte nbreColÀBP_AvantModif1) { /* Appelle le constructeur de 'AbstractTableModel'. This abstract class provides * default implementations for most of the methods in the TableModel interface. * https://docs.oracle.com/javase/7/docs/api/javax/swing/table/AbstractTableModel.html * Pas nécessaire car les méthodes requises sont implémentées dans cette sous-classe-ci. */ // super(); // this.nbreColÀBP2 = nbreColÀBP1; this.nbreColÀBP_AvantModif2 = nbreColÀBP_AvantModif1; // Instanciée ici aussi pour éviter 'NullPointerException' dans 'getRowCount()'. gestionnDonnéesTteLaTable = new ArrayList<>(); // Verticalement libellésColonnes = new ArrayList<>(); libellésColonnes.add("A"); libellésColonnes.add("B"); // Entre ces colonnes-ci viendront s'insérer celles des boutons-radios. libellésColonnes.add("Z"); // ((Byte) nbreColÀBP2).toString()); // Format des contenus des colonnes - Voir 'ajustageLargeurCol()' /* renduCellCol = new ArrayList(new Collection{"#.0", "#.0", "#.00"}); */ renduCellCol = new ArrayList(); renduCellCol.add("#.0"); // A renduCellCol.add("#.00"); // B // Entre ces colonnes-ci viendront s'insérer celles des boutons-radios. renduCellCol.add("#.0"); // C } /** Appelée - lors de l'initialisation, dans 'élaborTtsRangéesTable()', dans la boucle empilant des 'MonObjet's. */ @Override public void propertyChange(PropertyChangeEvent evt) { Object objet2 = evt.getSource(); if (objet2 == gestionObjDUneRang) { switch (evt.getPropertyName()) { case "objetsDUneTranPuiss": // 'supportChang_tPropri' // ((MonObjet) evt.getNewValue()).getSupportChangtPropri_Obj().addPropertyChangeListener(this); break; // MonModèleTable case "objectBijgevoegd": // Constructeur short wave2 = 0; // Rien que pour placer un breakpoint break; case "objectenVanEenRij": // Ne passe jamais par ici. short wave3 = 0; // Rien que pour placer un breakpoint break; // fireTableDataChanged(); case "dataVanEenRij": // Ne passe jamais par ici. short wave4 = 0; // Rien que pour placer un breakpoint break; } } else if (objet2 instanceof MonObjet) { switch (evt.getPropertyName()) { case "juistVeranderd": // Constructeur et utilisation short wave5 = 0; // Rien que pour placer un breakpoint break; case "ObjMgrDezeRijIsBijgevoegd": // Constructeur short wave6 = 0; // Rien que pour placer un breakpoint break; } ; // int idx_Tran = gestionObjDUneRang.getObjetsDUneRangée().indexOf(objet2); // short[] coordBR = ((MonObjet) objet2).getCoordBP(); // fireTableRowsUpdated(coordBR[0]-1, coordBR[0]-1); // Rien que la rangée concernée. } } /** Méthode exigée par l'interface 'AbstractTableModel' --> Nom en Anglais * Implements method from javax.swing.table.TableModel * @return libellésColonnes.size() */ @Override public int getColumnCount() { return libellésColonnes.size(); // return gestionObjDUneRang.getObjetsDUneRangée().size(); } /** Méthode exigée par l'interface 'AbstractTableModel' * 'gestionnDonnéesTteLaTable' doit avoir été instanciée dans la méthode-constructeur. * @return */ @Override public int getRowCount() { return gestionnDonnéesTteLaTable.size(); } // Méthode existante mais non exigée par l'interface 'AbstractTableModel' @Override public String getColumnName(int col) { return libellésColonnes.get(col); } /** If you did not specify a renderer for a particular column, then the table * invokes the table model's getColumnClass method, which gets the data type * of the column's cells. * Challenge : Le nombre de colonnes est variable. * @param colo * @return */ @Override public Class<?> getColumnClass(int colo) { if (colo < NBRE_FIXE_COL_AVANT) { return BigDecimal.class; } else if (colo >= NBRE_FIXE_COL_AVANT && // 2 colo < NBRE_FIXE_COL_AVANT + nbreColÀBP2) { return MonObjet.class; // Contient une propriété JRadioButton } else if (colo >= NBRE_FIXE_COL_AVANT + nbreColÀBP2 && colo < NBRE_FIXE_COL_AVANT + nbreColÀBP2 + NBRE_FIXE_COL_APRES) { return BigDecimal.class; } else // Sans 'else' ni ';' : "Confusing identation" return null; // Jamais } // Seules les colonnes à boutons-radios sont éditable. @Override public boolean isCellEditable(int rang, int col) { if (col < NBRE_FIXE_COL_AVANT) return false; else if (col >= NBRE_FIXE_COL_AVANT && col <= NBRE_FIXE_COL_AVANT + nbreColÀBP2) if (rang == 0) return false; else return true; else if (col > idxColFinBoutRadio) return false; return false; // Jamais } /** Méthode exigée par l'interface 'AbstractTableModel'. * Le contCellTabl renvoyé sera traité par la fonction * 'TableCellRenderer.getTableCellRendererComponent (JTable table, * Object value, boolean isSelected, boolean hasFocus, int row, int column)' * dans 'XYExtensTable_SSCCE'. * Renvoie un String ou un Boolean. */ @Override public Object getValueAt(int rang, int col) { Object contCellTabl = getValeurÀ(rang, col); if (col < NBRE_FIXE_COL_AVANT) { return contCellTabl; } else if (col >= NBRE_FIXE_COL_AVANT && col <= idxColFinBoutRadio) { // Bouton radio : Boolean boolean --> Boolean if ((Class<?>)contCellTabl.getClass() == MonObjet.class) { Boolean étaitSélect_é = ((MonObjet) contCellTabl).isSélectionné(); return étaitSélect_é; } } else if (col > idxColFinBoutRadio) { return contCellTabl; } ; // Sans 'else' ni ';' : "Confusing identation" return null; } // Méthode appelée par 'getValueAt() et 'setValueAt()'. Object getValeurÀ(int rang, int colo) { // Il y a [NBRE_RANG] gestionnObjetsDUneRangée dans 'gestionnDonnéesTteLaTable'. return gestionnDonnéesTteLaTable.get(rang).getObjetsDUneRangée().get(colo); } /** Need to implement this method because some table's data can be manually changed. * A pour but de n'activer ou désactiver le bouton-radio que d'une seule cellule de ¨* la table. Si c'est l'activer, les conséquences pour les autres cellules de la rangée * sont gérées par la méthode 'miseàjourTousBP_Rangée()' dans 'gestionnObjetsDUneRangée', * elle-même appelée ici par 'setSélectionné()' dans 'monObjet'. * Overrides method from javax.swing.table.AbstractTableModel */ @Override public void setValueAt(Object bpActionné, int idxRang2, int idxColo2) { if (idxColo2 >= NBRE_FIXE_COL_AVANT && idxColo2 <= idxColFinBoutRadio) { MonObjet contCellTabl = (MonObjet) getValeurÀ(idxRang2, idxColo2); contCellTabl.setSélectionné(Boolean.TRUE.equals(bpActionné)); } /* It works without 'fireTableCellUpdated(..;)' if you changes the data by * using the table editor, because once the editor is closed, the cell will * get repainted by the table. * However, if you manually invoke setValueAt() then it won't work. * Also if you don't invoke that method, the 'no event' will be fired for * a TableModelListener that might be added to the TableModel. */ fireTableCellUpdated(idxRang2, idxColo2); } List<GestionnObjetsDUneRangée> getDonnéesTteLaTable() // ArrayList<Object> { return gestionnDonnéesTteLaTable; } // - - - - - - - - - - - /** Méthode appelée dans 'miseÀJourModèleEtStructTable()'. * */ byte élaborTtsRangéesTable() { nbreColÀBP_AvantModif2 = nbreColÀBP2++; idxColFinBoutRadio = NBRE_FIXE_COL_AVANT + nbreColÀBP2 -1; // byte nbreCellulesChaqueRangée = (byte)(idxColFinBoutRadio + NBRE_FIXE_COL_APRES); MonObjet objet; // String libelNouvelleCol; // <editor-fold defaultstate="collapsed" desc="Insérer les libellés des colonnes aux boutons-radio"> if (nbreColÀBP2 > nbreColÀBP_AvantModif2) { for (byte nièmeCol = (byte) nbreColÀBP_AvantModif2 ; nièmeCol < nbreColÀBP2 ; nièmeCol++) { libellésColonnes.add(NBRE_FIXE_COL_AVANT + nièmeCol, /* libelNouvelleCol */ ((Byte) nièmeCol).toString()); } } else // Fin de 'if (nbreColÀBP2 > nbreColÀBP_AvantModif2)' // Suppression d'une colonne { /* Le nécessaire est fait par 'ajoutRetraitCol(int pos, byte nbreColÀBP2, * List columnData)' dans 'XYExtensTable_SSCCE' */ } // Fin de "Ajuster le nombre de colonnes de boutons-radios". // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Composer une série de valeurs factices pour les premières colonnes"> /* Avant d'élaborer les ArrayList 'gestionObjDUneRangée', élaborer * l'ArrayList 'échelleValeurs1eColonne'. */ BigDecimal uneValeur = new BigDecimal(10); final BigDecimal multiplicateur = new BigDecimal(1.414213); échelleValeurs1eColonne = new ArrayList<>(nbreColÀBP2); for (byte num = 0 ; num < (nbreColÀBP2 +1) ; num++) { uneValeur = uneValeur.multiply(multiplicateur); échelleValeurs1eColonne.add(uneValeur); } byte nbreRangées = (byte) (échelleValeurs1eColonne.size() -1); // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Composer la base des rangées de données de la table"> /* c à d la liste 'gestionnDonnéesTteLaTable' de toutes les listes 'gestionObjDUneRang' * de <nbreCellulesChaqueLigne> cellules, en fonction du nombre <nbreColÀBP>. * 'Object' est 'MonObjet' lorsqu'il s'agit des colonnes ajoutées dynamiquement. */ gestionnDonnéesTteLaTable = new ArrayList<>(nbreRangées); // 'idxRangée' est aussi utilisée par '@Override ... propertyChange(PropertyChangeEvent evt) for (idxRangée = 0 ; idxRangée < nbreRangées ; idxRangée++) { gestionObjDUneRang = new GestionnObjetsDUneRangée(nbreColÀBP2); /* Support pour propriété qui change. * Seule 'monModTable' est enregistrée comme "listener" (= guêteur) * de toutes les propriétés de * - chaque instanciation de 'gestionObjDUneRang' (dont 'objetsDUneTranPuiss') * cela dans de 'MonModTable' > ' * - chaque instanciation de 'MonObjet', cela dans la 'propertyChange()' */ /* Pour que le support de changement de propriété 'suppChanProp_GestRang' * propre à ce 'gestionObjDUneRang' enregistre 'MonModTable' comme guêteur * de changement de chacune des propriétés de ce 'gestionObjDUneRang'. */ // gestionObjDUneRangée.getSuppoChangePropri().addPropertyChangeListener(this); gestionObjDUneRang.ajoutGuêteurChangtPropri_GestRang(this); // Première colonne // Valeur de la deuxième cellules de la rangée précédente. gestionObjDUneRang.getObjetsDUneRangée().add(échelleValeurs1eColonne.get(idxRangée)); // Deuxième colonne gestionObjDUneRang.getObjetsDUneRangée().add(échelleValeurs1eColonne.get(idxRangée+1)); // Entre deuxième et dernière colonne for (byte col = NBRE_FIXE_COL_AVANT ; col < NBRE_FIXE_COL_AVANT + nbreColÀBP2 ; col++) { objet = new MonObjet(idxRangée, col); /* Pour que le support de changement de propriété 'suppChanProp_Obj' * propre à ce nouvel 'objet' enregistre 'monModTable' comme guêteur * de changement de chacune des propriétés de ce nouvel 'objet'. */ objet.ajoutGuêteurChangtPropri_Obj(this); /* Grâce à 'setGestionnObjetsDUneRangée(...)' dans 'ajoutObjetÀRangée(...)' * dans 'GestionnObjetsDUneRangée', la propriété 'gestionObjDUneRang2' dans * 'contCellTabl' réfèrera au 'gestionObjDUneRang' d'ici ('monModTable') */ gestionObjDUneRang.ajoutObjetÀRangée(objet); /* if (col == NBRE_FIXE_COL_AVANT) objet.setSélectionné(true); */ } // Dernière colonne gestionObjDUneRang.getObjetsDUneRangée().add(BigDecimal.ZERO); gestionnDonnéesTteLaTable.add(gestionObjDUneRang); /* L'activation initiale d'un bouton-radio par rangée n'est exécutable que * lorsque le tout dernier bouton-radio d'une rangée - c à d les [nbreColÀBP2] * objets - ont été ajoutés, c à d : * - au terme de l'empilement de tous les boutons-radios d'une rangée dans * 'Composer la base des rangées de données de la table'. * - au cours de l'utilisation de la table. * 'setSélectionné()' ne peut donc avoir lieu qu'ensuite. ((MonObjet) gestionObjDUneRang.getObjetsDUneRangée() .get(NBRE_FIXE_COL_AVANT)).setSélectionné(true); */ // The fireXxx() methods simply instruct the view to query the model via getValueAt(). // fireTableStructureChanged(); } // Fin de "Composer la base des rangées de données de la table" // </editor-fold>// </editor-fold> fireTableStructureChanged(); return nbreRangées; } }- MonObjet (104 l.)
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 /* * @author Chavadam * http://www.developpez.net/forums/d1577944/java/interfaces-graphiques-java/awt-swing/composants/tables/jtable-jradiobuttons-regroupes-rangee/ */ package xyextenstable_sscce; import java.beans.PropertyChangeSupport; // PropertyChangeEvent import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_AVANT; import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_APRES; // import static xyextenstable_sscce.XYExtensTable_SSCCE.DEBUG; /** Bean that support bound properties. (All Swing components are also beans) Manages a list of listeners and dispatches PropertyChangeEvents to them. Ce n'est pas que des boutons-radio (RenduEditeur_CellBoutRad) ont plusieurs guêteurs, mais que tous les boutons-radios ont un même guëteur. http://docs.oracle.com/javase/7/docs/api/java/beans/PropertyChangeSupport.html A bound property notifies listeners when its value changes. This has two implications: 1. This bean class includes 'addPropertyChangeListener()' [and 'removePropertyChangeListener()'] methods for managing the bean's listener(s) (here only 'MonModTable'). 2. When a bound property is changed (dans 'GestionnObjetsDUneRangée gestionObjDUneRang' et dans chaque 'MonObjet objet' créé dans 'MonModTable'), ainsi qu'à l'exécution de 'propertyChangeSupport.firePropertyChange()', the bean sends a PropertyChangeEvent to its registered listeners. Getter method but no setter : read-only property. La liste ... mais plutôt la partie centrale de l''List<ArrayList<Object>> objetsTteLaTable' dans 'MonModTable', c à d les colonnes après 'NBRE_FIXE_COL_AVANT' et avant 'NBRE_FIXE_COL_APRES'. Les deux dimensions de 'donnéesTteLaTable' sont variables. */ public class GestionnObjetsDUneRangée { /* Chaque rangée (objetsDUneRangée) contient des 'BigDecimal' et * un nombre variable de 'MonObjet' (contenant un 'JRadioButton'). */ private List<Object> objetsDUneRangée; // private final ButtonGroup groupeHorizBoutRad = new ButtonGroup(); private /* final */ PropertyChangeSupport suppChanProp_GestRang; /* Propriété en fait oommune à 'objetsDUneRangée', c à d qui ne devrait être * instanciée que dans l'entité englobant tous les 'gestionObjDUneRangée'. * Existe aussi dans 'monModTable'. */ private final byte nbreColÀBP1; GestionnObjetsDUneRangée(byte nbreColÀBP2) { // 'nbreColÀBP1' rien que pour 'miseàjourTousBR_Rangée()'. this.nbreColÀBP1 = nbreColÀBP2; objetsDUneRangée = new ArrayList<>( NBRE_FIXE_COL_AVANT + nbreColÀBP1 + NBRE_FIXE_COL_APRES); suppChanProp_GestRang = new PropertyChangeSupport(this); } public List<Object> getObjetsDUneRangée() { return objetsDUneRangée; } // Appelée par ? void setObjetsDUneRangée(List<Object> objetsDUneRangée2) { List<Object> ancienObjetsDUneRangée = objetsDUneRangée; this.objetsDUneRangée = objetsDUneRangée2; suppChanProp_GestRang.firePropertyChange("objectenVanEenRij", ancienObjetsDUneRangée, objetsDUneRangée); } /* Méthode appelée * - dans 'MonModTable' > 'élaborTtsRangéesTable()' * > 'Composer la base des rangées de données de la table' * Chaque rangée (objetsDUneRangée) contient des 'BigDecimal' et * un nombre variable de 'MonObjet' (contenant un 'RadioButton'). */ void ajoutObjetÀRangée(Object objet) { objetsDUneRangée.add(objet); // Met dans chaque objet la référence au gestionnaire d'objets qui le contient. if (objet != null) { ((MonObjet) objet).setGestionnObjetsDUneRangée(this); /* ((MonObjet) objet).getSupportChangtPropri().firePropertyChange("dataVanEenRij", null, ((MonObjet) objet).getGestionnObjetsDUneRangée()); */ suppChanProp_GestRang.firePropertyChange("objectBijgevoegd", null, (MonObjet) objet); } } /** Appelée par 'setSélectionné()' dans 'monObjet' et appelle 'setSélectionné()' * c à d fonction réentrante. * Met tous les boutons-poussoirs d'une rangée dans leurs états adéquats. * 'MonObjet' ne dispose pas de 'nbreColÀBP'; 'GestionObjDUneRang' bien. * @param objetActionné */ void miseàjourTousBR_Rangée(MonObjet objetActionné) { MonObjet obj; for (byte j = NBRE_FIXE_COL_AVANT ; j < NBRE_FIXE_COL_AVANT + nbreColÀBP1 ; j++) { obj = ((MonObjet) objetsDUneRangée.get(j)); obj.setSélectionné(objetActionné == obj); } } PropertyChangeSupport getSuppoChangePropri_GestRang() { return suppChanProp_GestRang; } void ajoutGuêteurChangtPropri_GestRang(PropertyChangeListener guêteur) { suppChanProp_GestRang.addPropertyChangeListener(guêteur); } void retraitGuêteurChangePropri_GestRang(PropertyChangeListener guêteur) { suppChanProp_GestRang.removePropertyChangeListener(guêteur); } }Bons "cut and paste"s.
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 /* * @author Chavadam */ package xyextenstable_sscce; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; // import static xyextenstable_sscce.XYExtensTable_SSCCE.DEBUG; /** Bean supporting bound properties. * La seule classe guêteuse (Listener) de 'MonObjet' est 'MonModTable'. */ class MonObjet { /* Delegating to 'suppChanProp_Obj' the management of a list of listeners * and the dispatching of 'PropertyChangeEvents' ? */ private boolean sélectionné; private GestionnObjetsDUneRangée gestionObjDUneRang; private final PropertyChangeSupport suppChanProp_Obj; public MonObjet(short idxRang, short idxColo) { suppChanProp_Obj = new PropertyChangeSupport(this); } // The accessor method to be defined uses 'is...' instead of 'get...' because boolean. boolean isSélectionné() { return sélectionné; } /** Appelée par * - le constructeur de 'MonModTable()'. * - 'setValueAt()' dans 'MonModTable()'. * - 'setSélectionné(objet)' dans 'gestionnObjetsDUneRangée'). * * @override setValueAt() > * getValeurÀ(idxRang2, idxColo2)).setSélectionné() > * gestionObjDUneRang2.miseàjourTousBR_Rangée() > * obj.setSélectionné() * miseàjourTousBR_Rangée() */ void setSélectionné(boolean sélectionné2) { if (this.sélectionné != sélectionné2) { // Ne passe par ici que s'il y a changement d'état. this.sélectionné = sélectionné2; if (sélectionné == true) { // Ne passe par ici que si le bouton-radio vient de passer à 'true'. /* 'gestionObjDUneRang' est devenu une référence concrète (non nulle) dans * le constructeur de 'MonModTable' par l'appel de 'gestionObjetsDUneRangée'. * ajoutObjetÀRangée()' qui contient l'appel de 'objet.setGestionnObjetsDUneRangée()'. */ gestionObjDUneRang.miseàjourTousBR_Rangée(this); } suppChanProp_Obj.firePropertyChange("juistVeranderd", !sélectionné, sélectionné); } } // Méthode appelée par 'ajoutObjetÀRangée(Object objet)' dans 'GestionnObjetsDUneRangée'. void setGestionnObjetsDUneRangée(GestionnObjetsDUneRangée gestionnObjetsDUneRangée2) { GestionnObjetsDUneRangée ancienGestionnObjetsDUneRangée = gestionObjDUneRang; /* Une référence au conteneur de l'objet (gestionObjDUneRang) est placée * dans chaque objet afin ... */ this.gestionObjDUneRang = gestionnObjetsDUneRangée2; suppChanProp_Obj.firePropertyChange("ObjMgrDezeRijIsBijgevoegd", ancienGestionnObjetsDUneRangée, gestionnObjetsDUneRangée2); } // Méthode appelée par 'ajoutObjetÀRangée(MonObjet objet)' dans 'GestionnObjetsDUneRangée'. GestionnObjetsDUneRangée getGestionnObjetsDUneRangée() { return gestionObjDUneRang; } PropertyChangeSupport getSupportChangtPropri_Obj() { return suppChanProp_Obj; } // Ici, le 'guêteur' (= 'listener') est 'monModTable' void ajoutGuêteurChangtPropri_Obj(PropertyChangeListener guêteur) { suppChanProp_Obj.addPropertyChangeListener(guêteur); } void retraitGuêteurChangePropri_Obj(PropertyChangeListener guêteur) { suppChanProp_Obj.removePropertyChangeListener(guêteur); } }
P.S.: À maîtriser : JTables - Un autre regard
Partager