Bonjour,

Ayant besoin d'un textField avec autoComplétion, j'ai codé la classe ci dessous. Elle fonctionne convenablement (manque un tri de la jlist par exemple) mais loin d'être un expert, je sollicite vos avis pour l'améliorer. Et puis elle pourra toujours servir à d'autres

Le code est assez long mais rien de difficile ni tordu (je pense ).
Seul requis pour fonctionner convenablement, les objets passés en paramètre doivent avoir leur méthode toString() de redéfini afin d'afficher quelque chose de compréhensible.

Merci à vous.


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
 
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
 
public class AutoCompleteTextField extends JPanel {
    private static final long serialVersionUID = -8117159999334693538L;
 
    //Liste composée de tous les objets disponibles
    private List<Object> _listAllObjects; 
 
    //Composants
    private JList _jlistPropositions;
    private JTextField _textField;
    private DefaultListModel _objetAAfficher;
    private JScrollPane _scrollPaneListe;
    private JPopupMenu _popUpListe;
 
    //Listener
    private caretListener _caretListener = new caretListener();
    private keyListener _keyListener = new keyListener();
    private mouseListener _mouseListener = new mouseListener();
 
    //Variables utilisés dans les listener (évite d'en instancier à chque fois une nouvelle)
    private String _rechercheUser;
    private int _positionPopUpMenuX;
    private int _positionPopUpMenuY;
    private int _selectedIndex;
 
    private boolean _activationCaretListener = true;
 
    //Variables utilisées pour calculer la largeur du JPopupMenu
    private final int NBR_PIXEL_PAR_CARACTERE = 7;
    private int _maxCaracteres = 0;
 
    //********************************************************
    //CONSTRUCTEURS
    //********************************************************
    public AutoCompleteTextField(List listeChoix) {
	super();
	_listAllObjects = listeChoix;
	init(null);
    }
 
    public AutoCompleteTextField(List<Object> listeChoix, String label) {
	super();
	_listAllObjects = listeChoix;
	init(label);
    }
 
 
 
    //********************************************************
    //METHODES PUBLIQUES
    //********************************************************
    /**
     * Retourne l'objet sélectionnée
     */
    public Object getSelectedValue(){
	return _jlistPropositions.getSelectedValue();
    }
 
 
 
    //********************************************************
    //METHODES PRIVEES
    //********************************************************
    private void init(String label){
	//Calcul de la largeur du jpopupmenu
	for (Object objet : _listAllObjects){
	    if (objet.toString().length() > _maxCaracteres)
		_maxCaracteres = objet.toString().length();
	}
 
 
	// Configuration du panel
	GridBagLayout gbl = new GridBagLayout();
	this.setLayout(gbl);
	this.setVisible(true);
	this.setOpaque(false);
 
	// Création et Configuration du textField
	_textField = new JTextField(20);
	_textField.addCaretListener(_caretListener);
	_textField.addKeyListener(_keyListener);
 
	// Création du ListModel;
	_objetAAfficher = new DefaultListModel();
 
	// Création de la JList
	_jlistPropositions = new JList(_objetAAfficher);
	_jlistPropositions.setLayoutOrientation(JList.VERTICAL);
	_jlistPropositions.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
	_jlistPropositions.setAutoscrolls(true);
	_jlistPropositions.setVisibleRowCount(7);
	_jlistPropositions.addMouseListener(_mouseListener);
	_scrollPaneListe = new JScrollPane(_jlistPropositions);
 
	_popUpListe = new JPopupMenu();
	Dimension dim = new Dimension(_maxCaracteres*NBR_PIXEL_PAR_CARACTERE,150);
	_popUpListe.setPreferredSize(dim);
	_popUpListe.setVisible(false);
	_popUpListe.add(_scrollPaneListe);
 
 
	// Ajout des composants
	GridBagConstraints gbc = new GridBagConstraints();
 
	//Si il faut un label
	if(label != null){
	    gbc.gridx = 0;
	    gbc.gridy = 0;
	    gbc.weightx = 1;
	    gbc.insets = new Insets(0, 0, 0, 5);
	    gbc.anchor = GridBagConstraints.FIRST_LINE_START;
	    this.add(new JLabel(label), gbc);
	}
 
	gbc.gridx = 1;
	gbc.gridy = 0;
	gbc.weightx = 1;
	gbc.weighty = 1;
	gbc.gridwidth = GridBagConstraints.REMAINDER;
	gbc.gridheight = GridBagConstraints.RELATIVE;
	gbc.anchor = GridBagConstraints.LINE_START;
	gbc.insets = new Insets(0, 0, 0, 0);
	gbc.anchor = GridBagConstraints.WEST;
	this.add(_textField, gbc);
    }
 
 
 
 
    //********************************************************
    //LISTENER
    //********************************************************
    class caretListener implements CaretListener {
	@Override
	public void caretUpdate(CaretEvent e) {
	    if (_activationCaretListener){
		// Récupération de la recherche de l'utilisateur
		_rechercheUser = _textField.getText().toUpperCase();
 
		// On parcourt les objets de _listeChoixSourceToString et
		// on supprime de _listeProposition les choix qui ne correspondent pas
		// à la recherche de l'utilisateur
		for (Object objet : _listAllObjects) {
		    if (!objet.toString().toUpperCase().contains(_rechercheUser)) {
			_objetAAfficher.removeElement(objet);
		    } else {
			if (!_objetAAfficher.contains(objet)){
			    _objetAAfficher.addElement(objet);
			}
		    }
		}
 
//		 Affichage de la JList seulement si au moins une lettre est renseignée
		if (e.getDot() >= 1 && !_objetAAfficher.isEmpty()){
		    if (!_popUpListe.isVisible()){
			_popUpListe.setVisible(true);
			_positionPopUpMenuX = _textField.getLocationOnScreen().x;
			_positionPopUpMenuY = _textField.getLocationOnScreen().y + _textField.getHeight();
			_popUpListe.setLocation(_positionPopUpMenuX,_positionPopUpMenuY);
		    }
		}else
		    _popUpListe.setVisible(false);
	    }
 
	}
    }
 
    class keyListener implements KeyListener {
	@Override
	public void keyPressed(KeyEvent e) {
	    _selectedIndex = _jlistPropositions.getSelectedIndex();
	    // Si touche bas
	    if (e.getKeyCode() == 40) {
		_selectedIndex = _jlistPropositions.getSelectedIndex() + 1;
		_jlistPropositions.setSelectedIndex(_selectedIndex);
		_jlistPropositions.ensureIndexIsVisible(_selectedIndex);
	    }
 
	    // Si touche haut
	    else if (e.getKeyCode() == 38) {
		if (_jlistPropositions.getSelectedIndex() != 0) {
		    _selectedIndex = _jlistPropositions.getSelectedIndex() - 1;
		    _jlistPropositions.setSelectedIndex(_selectedIndex);
		    _jlistPropositions.ensureIndexIsVisible(_selectedIndex);
		}
	    }
 
	    // Si touche entrée
	    else if (e.getKeyCode() == 10) {
		//On desactive le caretListener pour éviter de refaire une boucle sur les objet
		_activationCaretListener = false;
		_textField.setText(_jlistPropositions.getSelectedValue().toString());
		_activationCaretListener = true;
		_popUpListe.setVisible(false);
	    }
	}
 
	@Override
	public void keyTyped(KeyEvent e) {}
 
	@Override
	public void keyReleased(KeyEvent e) {}
 
    }
 
    class mouseListener implements MouseListener{
 
	@Override
	public void mouseClicked(MouseEvent e) {
	    //On desactive le caretListener pour éviter de refaire une boucle sur les objet
	    _activationCaretListener = false;
	    _textField.setText(_jlistPropositions.getSelectedValue().toString());
	    _activationCaretListener = true;
	    _popUpListe.setVisible(false);
	}
 
	@Override
	public void mousePressed(MouseEvent e) {}
 
	@Override
	public void mouseReleased(MouseEvent e) {}
 
	@Override
	public void mouseEntered(MouseEvent e) {}
 
	@Override
	public void mouseExited(MouseEvent e) {}
 
    }
 
 
    //********************************************************
    //POUR TESTS
    //********************************************************
    public static void main(String args[]) {
	final JFrame frame = new JFrame("Autocomplete");
	frame.setSize(250,300);
	JPanel panel = new JPanel();
	frame.setContentPane(panel);
 
	List listTest = new ArrayList();
	listTest.add("Javadoc");
	listTest.add("JAVA");
	listTest.add("Developpez.net");
	listTest.add("Developpement");
	listTest.add("Analyste");
	listTest.add("Programmeur");
	listTest.add("Energie");
	listTest.add("Coder");
	listTest.add("Eclipse");
	listTest.add("Programmer");
	listTest.add("Analyser");
	listTest.add("ezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzze");
 
	final AutoCompleteTextField acd = new AutoCompleteTextField(listTest);
	panel.add(acd);
 
	JButton boutonValider = new JButton("Valider");
	boutonValider.addActionListener(new ActionListener(){
	    @Override
	    public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(frame, acd.getSelectedValue());
	    }
	});
	panel.add(boutonValider);
	frame.setVisible(true);
    }
 
}