JComboBox 需要灵活的 Java 键/值集合类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2095140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Need flexible Java key/value collection class for JComboBox
提问by craig
I have a model class that stores keys and values:
我有一个存储键和值的模型类:
public class KeyValue {
private Object key;
private String value;
KeyValue () {
}
KeyValue (Object key, String value) {
this.key=key;
this.value=value;
}
public Object getKey() {
return this.key;
}
public void setKey(Object key) {
this.key=key;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value=value;
}
@Override
public String toString() {
return this.value;
}
}
I use this class to populate a JComboBox's Model:
我使用这个类来填充 aJComboBox的模型:
for (int i = 0; i < universes.length; i++) {
ComboBox_Universes.addItem(new KeyValue(infoObject.ID,infoObject.title));
}
I would like to refactor this logic to use a Java collection class (call it KeyValueCollection) that can support two objectives:
我想重构此逻辑以使用KeyValueCollection可以支持两个目标的 Java 集合类(称为):
1) the KeyValueCollectioncan be used to populate the JComboBox's Model. Something like:
1)KeyValueCollection可用于填充JComboBox的模型。就像是:
//get a KeyValueCollection filled with data from helper class
KeyValueCollection universeCollection = Repository.getUniverseCollection();
//use this collection as the JComboBox's model
ComboBox_Universes.setModel(universeCollection);
2) I can use the KeyValueCollectionto convert a key to a value:
2)我可以使用KeyValueCollection将键转换为值:
//ID retrieve from another control
int universeID = (int)this.Table_Values.getModel().getValueAt(row, COLUMN_ID);
//convert ID to name
String universeName = universeCollection.get(universeID).getValue();
In the .NET world, I would use the KeyedCollection class for this, but I'm not very familiar with Java.
在 .NET 世界中,我会为此使用 KeyedCollection 类,但我对 Java 不是很熟悉。
Help is greatly appreciated.
非常感谢帮助。
回答by Laurent K
You can use a custom class like this one (run main function to see its behavior) :
您可以使用这样的自定义类(运行 main 函数以查看其行为):
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
public class KeyValueComboboxModel extends AbstractListModel implements ComboBoxModel, Map<String, String> {
private TreeMap<String,String> values = new TreeMap<String,String>();
private Map.Entry<String, String> selectedItem = null;
public Object getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(Object anItem) {
this.selectedItem = (java.util.Map.Entry<String, String>) anItem;
fireContentsChanged(this, -1, -1);
}
public Object getElementAt(int index) {
List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(values.entrySet());
return list.get(index);
}
public int getSize() {
return values.size();
}
public void clear() {
values.clear();
}
public boolean containsKey(Object key) {
return values.containsKey(key);
}
public boolean containsValue(Object value) {
return values.containsValue(value);
}
public Set<java.util.Map.Entry<String, String>> entrySet() {
return values.entrySet();
}
public String get(Object key) {
return values.get(key);
}
public Set<String> keySet() {
return values.keySet();
}
public String put(String key, String value) {
return values.put(key, value);
}
public String remove(Object key) {
return values.remove(key);
}
public int size() {
return values.size();
}
public Collection<String> values() {
return values.values();
}
public boolean isEmpty() {
return values.isEmpty();
}
public void putAll(Map<? extends String, ? extends String> m) {
values.putAll(m);
}
private static String entryToString(Map.Entry<String, String> entry) {
String str = "" + entry.getKey() + "->" + entry.getValue();
return str;
}
public static void main(String[] args) {
Map<String,String> map= new HashMap<String,String>(){{
put("1","blue");
put("2","red");
put("3","white");
put("4","black");
}};
JFrame f = new JFrame();
f.setContentPane(new JPanel(new BorderLayout()));
KeyValueComboboxModel model = new KeyValueComboboxModel();
model.putAll(map);
final JComboBox combo = new JComboBox(model);
combo.setRenderer(new DefaultListCellRenderer(){
@Override
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
if(value instanceof Map.Entry){
Map.Entry<String,String> entry = (java.util.Map.Entry<String, String>) value;
String str = entryToString(entry);
return super.getListCellRendererComponent(list, str, index, isSelected, cellHasFocus);
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
});
final JLabel lab = new JLabel("Nothing selected");
combo.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
if(combo.getSelectedItem()!=null){
lab.setText(entryToString((java.util.Map.Entry<String, String>) combo.getSelectedItem()));
} else {
lab.setText("");
}
}
});
f.getContentPane().add(combo,BorderLayout.CENTER);
f.getContentPane().add(lab,BorderLayout.SOUTH);
f.setSize(300,80);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
EDIT : to handle the selected item and keys, you may add these methods:
编辑:要处理选定的项目和键,您可以添加以下方法:
public void setSelectedKey(String key){
selectedItem = values.ceilingEntry(key);
setSelectedItem(key);
}
public void setSelectedItem(String key, String value){
values.put(key, value);
setSelectedKey(key);
}
By default, values are ordered following the natural order of the keys (alphabetical order of the keys, here, because these are String). If you need an other ordering, add a java.util.Comparatorto the TreeMap(see TreeMap documentation).
默认情况下,值按照键的自然顺序排序(键的字母顺序,在这里,因为它们是String)。如果您需要其他排序,请将 a 添加java.util.Comparator到TreeMap(请参阅 TreeMap 文档)。
回答by Laurence Gonsalves
Your second requirement suggests that you want a Map, but ComboboxModelis a ListModel, which suggests that you'll want to be able to efficiently retrieve elements by "index".
您的第二个要求表明您需要一个Map,但ComboboxModel是一个ListModel,这表明您希望能够通过“索引”有效地检索元素。
I don't believe any of the standard collections can do this for you as simply as you'd like. You can either create a Map, and then copy the values to a separate List/ComboboxModel, or you could use something like IndexedList(a List implementation that maintains an index Map).
我不相信任何标准集合都可以像您希望的那样简单地为您做到这一点。您可以创建一个 Map,然后将值复制到单独的 List/ComboboxModel,或者您可以使用类似IndexedList(维护索引 Map 的 List 实现)。
回答by KLE
The Map (implementation HashMap) is a Key-Value class.
Map(实现HashMap)是一个Key-Value类。
It converts from key to value using the method #get.
它使用#get 方法从键转换为值。
There are also method to access all keys, all values and so on. So you should have no problem to fill a model with it.
还有访问所有键、所有值等的方法。所以用它填充模型应该没有问题。
It also contains a Key-Value pair that is called Map.Entry.
它还包含一个称为 Map.Entry 的键值对。
回答by Bozho
What about java.util.Mapimplementations?
怎么样java.util.Map实现?
with HashMap, for example, you can have:
用HashMap,例如,你可以有:
Map<Object, String> map = new HashMap<Object, String>();
map.put(key, value);
Object value = map.get(key);
However, you can't directly populate the JComboBoxwith the Map. You can add all keys to the JComboBox, and then get the corresponding values when needed. Adding can be done in many ways, two of which:
但是,您不能直接JComboBox使用Map. 您可以将所有键添加到 中JComboBox,然后在需要时获取相应的值。添加可以通过多种方式完成,其中两种:
new JComboBox(map.keySet().toArray(new Object[]));by a loop:
for (Object key : map.keySet() { comboBox.addItem(key); }
new JComboBox(map.keySet().toArray(new Object[]));通过循环:
for (Object key : map.keySet() { comboBox.addItem(key); }
回答by Itay Maman
I think that a plain HashMap<Object,String>can address most of your needs:
我认为平原HashMap<Object,String>可以满足您的大部分需求:
// Build the map
Map<Object,String> map = new HashMap<Object,String>();
for(InfoObject io : universes)
map.put(io.ID,io.title);
// Populate the ComboBox
for(String s : map.values())
ComboBox_Universes.addItem(s);
// Convert ID to name
int universeID = (int)this.Table_Values.getModel().getValueAt(row, COLUMN_ID);
String universeName = map.get(universeID);
回答by DejanLekic
I use the following code:
我使用以下代码:
/**
* This class is slightly modified version of the Pair class from this thread:
* http://stackoverflow.com/questions/156275/what-is-the-equivalent-of-the-c-pairl-r-in-java
* As suggested in the thread above, I have made first & second to be final members.
* I have made it into an Map.Entry<K,V> type, so it is suitable to be an element
* of any Java Hash map...
*
* @author Dejan Lekic - http://dejan.lekic.org
*/
public class Pair<KeyT, ValueT> implements Map.Entry<KeyT, ValueT> {
protected KeyT first;
protected ValueT second;
public Pair(final KeyT argFirst, final ValueT argSecond) {
super();
this.first = argFirst;
this.second = argSecond;
}
@Override
public int hashCode() {
int hashFirst = (first != null) ? first.hashCode() : 0;
int hashSecond = (second != null) ? second.hashCode() : 0;
return (hashFirst + hashSecond) * hashSecond + hashFirst;
}
@Override
public boolean equals(final Object other) {
if (other instanceof Pair) {
Pair otherPair = (Pair) other;
return ((this.first == otherPair.first
|| (this.first != null && otherPair.first != null
&& this.first.equals(otherPair.first)))
&& (this.second == otherPair.second
|| (this.second != null && otherPair.second != null
&& this.second.equals(otherPair.second))));
} // if
return false;
} // equals() method
@Override
public String toString() {
// previously we used " - " as a separator. Now we will use the 0x1f character, called the UNIT
// SEPARATOR to separate two fields in a String object. See the Sise class for more information.
return first + "\u001f" + second;
}
public KeyT getFirst() {
return first;
}
public void setFirst(final KeyT argFirst) {
this.first = argFirst;
}
public ValueT getSecond() {
return second;
}
public void setSecond(final ValueT argSecond) {
this.second = argSecond;
}
@Override
public ValueT setValue(final ValueT argNewValue) {
ValueT oldValue = second;
second = argNewValue;
return oldValue;
}
@Override
public ValueT getValue() {
return second;
}
@Override
public KeyT getKey() {
return first;
}
} // Pair class
// $Id: Pair.java 149 2012-01-13 12:30:59Z dejan $

