Na poczatek kod:
package test;
import java.awt.Component;
import java.awt.FlowLayout;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
public class LocaleTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JComboBox combo = new JComboBox(new LocaleModel());
combo.setRenderer(new LocaleRenderer());
frame.add(combo);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
class LocaleModel extends AbstractListModel implements ComboBoxModel {
private Locale[] locales;
private Locale selected;
public LocaleModel() {
locales = Locale.getAvailableLocales();
Arrays.sort(locales, new Comparator<Locale>() {
@Override
public int compare(Locale o1, Locale o2) {
return o1.getDisplayName().compareTo(o2.getDisplayName());
}
});
selected = Locale.getDefault();
}
@Override
public Locale getElementAt(int index) {
return locales[index];
}
@Override
public int getSize() {
return locales.length;
}
@Override
public Locale getSelectedItem() {
return selected;
}
@Override
public void setSelectedItem(Object anItem) {
selected = (Locale) anItem;
}
}
class LocaleRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Locale l = (Locale) value;
return super.getListCellRendererComponent(list, l.getDisplayName(), index, isSelected, cellHasFocus);
}
}
Kod wyswietla kombo z alfabetycznie posortowanymi localami, posortowanymi wg getDisplayName(). Mam wlasny model i wlasnego renderera - model przechowuje obiekty Locale, a renderer pokazuje ich getDisplayName(). Ladnie dziala, jest tylko 1 problem. Rozwincie liste, i wcisnijcie kilka razy literke H - wlaczy sie wyszukiwanie w liscie wg literek - wyszuka po kolei Hindi, Hungarian, Hungarian (Hungary) (poki co ladnie) i teraz zonk - wyszukuje rowniez Croatian i Croatian (Croatia) (uzywam angielskiego locale). Wynika to z tego ze kod Locale dla Chorwacji to hr.
Przyjrzalem sie sprawie nieco blizej i oto co znalazlem: klasa BasicComboBoxUI ma klase wewnetrzna DefaultKeySelectionManager, ktora ma metode selectionForKey() uruchamiana gdy wciskamy klawisz przy rozwinietej liscie kombo. Ona wewnetrznie korzysta z JList (linijka 1947 w kodzie bibliotek javy 1.6u15), konkretnie metode getNextMatch(), ktora to z kolei wykorzystuje dostarczony przeze mnie model. Logika tam jest taka ze w petli (poczatek to aktualnie zaznaczony indeks +1) pobierane sa elementy modelu i zamieniane na String, i nastepnie sprawdzane czy wcisnieta przez usera literka jest pierwsza literka tego stringa.
Troche lipa bo np moj renderer nie wyswietla Locale.toString() tylko Locale.getDisplayName(), i stad takie dziwne rzeczy wychodza. Co wiecej, mozna sobie wyobrazic modele ktorych elementy zupelnie nie beda sie nadawac zeby zwracac sensowna wartosc z toString(), a wyszukiwanie po literkach nadal bedzie dzialac.
W koncu pytanie - czy ktos wie jak to zmienic na takie dzialanie jak chce, bez wielkiego hakowanai Swinga? Nie wpadlem poki co na nic oczywistego, moze ktos juz wczesniej tym sie zajmowal.
Pozdrawiam.