2010-01-19 54 views
1

靈活的Java鍵/值集合類我有一個存儲密鑰和值的模型類:極品的JComboBox

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; 
    } 

} 

我使用這個類來填充JComboBox的型號:

for (int i = 0; i < universes.length; i++) { 
    ComboBox_Universes.addItem(new KeyValue(infoObject.ID,infoObject.title)); 
} 

我想重構這個邏輯來使用Java集合類(稱爲KeyValueCollection),它可以支持兩個目標:

1)KeyValueCollection可以是u sed來填充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)我可以使用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(); 

在.NET的世界裏,我會用這個KeyedCollection類的,但我對Java不太熟悉。

非常感謝幫助。

回答

3

您可以使用自定義類像這樣的(運行的主要功能,看它的行爲):

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); 


    } 


} 

編輯:處理所選的項目和按鍵,您可以添加這些方法:

public void setSelectedKey(String key){ 
    selectedItem = values.ceilingEntry(key); 
    setSelectedItem(key); 
} 

public void setSelectedItem(String key, String value){ 
    values.put(key, value); 
    setSelectedKey(key); 
} 

默認情況下,值按照鍵的自然順序排列(按鍵的字母順序,這裏是String)。如果您需要其他訂購,請將java.util.Comparator添加到TreeMap(請參閱TreeMap文檔)。

+0

三個問題: 1.什麼是設置SelectedItem的語法?這個Foo的一部分是[foo]我......對不起。 Map.Entry item = new Foo (「2」,「red」); model.setSelectedItem(item); 2.如果我想要一個setSelectedKey()方法,那麼我需要從TreeMap中找到正確的Map.Entry,然後調用setSelectedItem,是否正確? 3.理想情況下,組合框的值將按字母順序排序。我假設我需要對HashMap的值進行排序。還有另一種更簡單的方法嗎? – craig 2010-01-22 03:56:59

+0

@克雷格:我希望我的編輯能夠滿足您的需求。 – 2010-01-22 09:17:58

+0

應該不是setSelectedKey()方法讀: 公共無效setSelectedKey(String鍵){ //調用設置變量和觸發事件 setSelectedItem(values.ceilingEntry(鍵))的方法; } – craig 2010-01-22 14:06:59

1

Map(實現HashMap)是一個Key-Value類。

它使用方法#get將鍵值轉換爲值。

還有訪問所有鍵,所有值等的方法。所以你應該沒有問題用它來填充模型。

它還包含一個名爲Map.Entry的鍵值對。

1

那麼java.util.Map實現呢?

HashMap,例如,你可以有:

Map<Object, String> map = new HashMap<Object, String>(); 
map.put(key, value); 
Object value = map.get(key); 

但是,你不能直接填充JComboBoxMap。您可以將所有密鑰添加到JComboBox,然後在需要時獲取相應的值。將可以通過多種方式來實現,其中兩個:

  • new JComboBox(map.keySet().toArray(new Object[]));
  • 通過一個循環:

    for (Object key : map.keySet() { 
        comboBox.addItem(key); 
    } 
    
+0

+1我找到了另一種情況,您的評論非常有用。 – craig 2012-01-24 14:43:21

0

我認爲,一個普通的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); 
1

您的第二個要求是su ggests,你想要一個Map,但ComboboxModelListModel,這表明你希望能夠通過「索引」有效地檢索元素。

我不相信任何標準集合都可以爲你做到這一點,只要你願意。您可以創建一個Map,然後將這些值複製到一個單獨的List/ComboboxModel,或者您可以使用類似IndexedList(維護索引Map的List實現)之類的東西。

0

我使用下面的代碼:

/** 
* 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 $