Hallo.
Also ich wollte in mein Programm eine JComboBox einbauen, aus der man eine vorher festgelegte Menge an Strings wählen kann. Da das jedoch einige sind, wollte ich das ganze mit eingebauter Suchfunktion machen. Ich habs nicht hinbekommen, da ich mit sowas schon lange ncihts mehr zu tun hatte und davor auch nur mit Müh was hinbekommen habe. Also habe ich eine vorgefertigte Klasse genommen, die genau das macht:
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.JComboBox;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
/**
*
* JComboBox with an autocomplete drop down menu. This class is hard-coded for
* String objects, but can be
*
* altered into a generic form to allow for any searchable item.
*
*
* @author G. Cope
*
*
*
*/
public class AutocompleteJComboBox extends JComboBox {
static final long serialVersionUID = 4321421L;
private final Searchable<String, String> searchable;
/**
*
* Constructs a new object based upon the parameter searchable
*
* @param s
*
*/
public AutocompleteJComboBox(Searchable<String, String> s) {
super();
this.searchable = s;
setEditable(true);
Component c = getEditor().getEditorComponent();
if (c instanceof JTextComponent) {
final JTextComponent tc = (JTextComponent) c;
tc.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent arg0) {
}
@Override
public void insertUpdate(DocumentEvent arg0) {
update();
}
@Override
public void removeUpdate(DocumentEvent arg0) {
update();
}
public void update() {
//perform separately, as listener conflicts between the editing component
//and JComboBox will result in an IllegalStateException due to editing
//the component when it is locked.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
List<String> founds = new ArrayList<>(searchable.search(tc.getText()));
Set<String> foundSet = new HashSet<>();
for (String s : founds) {
foundSet.add(s.toLowerCase());
}
Collections.sort(founds);//sort alphabetically
setEditable(false);
removeAllItems();
//if founds contains the search text, then only add once.
if (!foundSet.contains(tc.getText().toLowerCase())) {
addItem(tc.getText());
}
for (String s : founds) {
addItem(s);
}
setEditable(true);
setPopupVisible(true);
tc.requestFocus();
}
});
}
});
//When the text component changes, focus is gained
//and the menu disappears. To account for this, whenever the focus
//is gained by the JTextComponent and it has searchable values, we show the popup.
tc.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent arg0) {
if (tc.getText().length() > 0) {
setPopupVisible(true);
}
}
@Override
public void focusLost(FocusEvent arg0) {
}
});
} else {
throw new IllegalStateException("Editing component is not a JTextComponent!");
}
}
}
Ich hab vor, das ganze noch anzupassen und zwar so wie es im Kommentar steht: es allgemein mit Diamond-Operatoren zu machen. Aber davor wollte ich es erstmal hinkriegen, das es so passt wie ich es will. Einen kleinen Fix zum Original habe ich schon drinne, er verliert also beim tippen nicht mehr den Focus. Aber es hat noch nen Schönheitsfehler, den ich jetz bei ca ner Stunde rumprobieren nicht hinbekommen habe: Wenn man nach einem String sucht und es mehrere Ergebnisse gibt und man diese gewohnter Weise mit den Pfeiltasten auswählen möchte, zeigt er beim erreichen des ersten Ergebnisses nur noch dieses an. Ich gehe daher davon aus, das er das mit den Pfeiltasten ebenso sofort updatet und das erste Ergebnis als suchwort versteht und daher dann auch nur noch dieses findet.
Das ist aber nicht so ganz was ich möchte. Ich möchte das man suchen kann und dann mit den Pfeiltasten auswählen. Er soll also die Pfeiltasten im Bezug auf das suchen/Autovervollständigen ignorieren. Aber irgendwie bekomme ich das nciht hin. Wer von euch rat?
Edit: Ich merke grade was: Sobald man 2 oder mehr Buchstaben beim suchen eingibt, funktioniert es so. Aber nicht wenn man nur nach einem gesucht hat.
*** Edit ***
Habs mir viel zu kompliziert gemacht:
public void insertUpdate(DocumentEvent arg0) {
System.out.println("Insert: " + arg0.getLength());
if (arg0.getLength() == 1) {
System.out.println("Update");
update();
}
}
@Override
public void removeUpdate(DocumentEvent arg0) {
System.out.println("Remove: " + arg0.getLength());
if (arg0.getLength() == 1) {
if (tc.getText().length() > 0) {
System.out.println("Update2: " + tc.getText().length());
update();
}
}
}```
Das wars, jetz funktionierts wie es soll