2010-01-19 5 views
1

J'ai une classe de modèle qui stocke les clés et les valeurs:Besoin souple clé Java/valeur classe de collection pour 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; 
    } 

} 

-je utiliser cette classe pour remplir un modèle de JComboBox:

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

Je voudrais refactoriser cette logique pour utiliser une classe de collection Java (appelez-le KeyValueCollection) qui peut supporter deux objectifs:

1) le KeyValueCollection peut être u sed pour remplir le modèle JComboBox. Quelque chose comme:

//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) Je peux utiliser la KeyValueCollection pour convertir une clé à une valeur:

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

Dans le monde .NET, j'utiliser la classe KeyedCollection pour cela, mais je Je ne suis pas très familier avec Java.

L'aide est grandement appréciée.

Répondre

3

Vous pouvez utiliser une classe personnalisée comme celui-ci (exécuter la fonction principale pour voir son comportement):

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: pour gérer l'élément sélectionné et les touches, vous pouvez ajouter ces méthodes:

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

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

Par défaut, les valeurs sont triées en fonction de l'ordre naturel des touches (ordre alphabétique des clés, ici String). Si vous avez besoin d'un autre ordre, ajoutez un java.util.Comparator au TreeMap (voir la documentation de TreeMap).

+0

Trois questions: 1. Quelle est la syntaxe de définition de SelectedItem? La partie Foo de ça c'est [foo] moi ... Désolé. Map.Entry item = nouveau Foo ("2", "red"); model.setSelectedItem (item); 2. Si je voulais une méthode setSelectedKey(), alors je devrais trouver le Map.Entry correct à partir de TreeMap, puis appeler setSelectedItem, correct? 3. Idéalement, les valeurs de la combobox seraient triées par ordre alphabétique. Je suppose que j'ai besoin de trier les valeurs de HashMap. Y a-t-il un autre moyen plus simple? – craig

+0

@Craig: J'espère que mon édition répondra à vos besoins. Si –

+0

pas la méthode setSelectedKey() lire: setSelectedKey public void (String key) {// appeler la méthode qui définit la variable et déclenche l'événement setSelectedItem (values.ceilingEntry (clé)); } – craig

1

La carte (implémentation HashMap) est une classe valeur-clé.

Il convertit de la clé en valeur en utilisant la méthode #get.

Il existe également une méthode pour accéder à toutes les clés, toutes les valeurs, etc. Vous ne devriez donc pas avoir de problème pour remplir un modèle avec.

Il contient également une paire valeur-clé appelée Map.Entry.

1

Qu'en est-il des implémentations java.util.Map?

avec HashMap, par exemple, vous pouvez avoir:

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

Cependant, vous ne pouvez pas remplir directement le JComboBox avec le Map. Vous pouvez ajouter toutes les clés au JComboBox, puis obtenir les valeurs correspondantes si nécessaire. Ajout peut être fait de plusieurs façons, dont deux:

  • new JComboBox(map.keySet().toArray(new Object[]));
  • par une boucle:

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

+1 J'ai trouvé votre commentaire utile pour une autre situation. – craig

0

Je pense qu'une HashMap<Object,String> plaine peut répondre à la plupart de vos besoins:

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

Votre deuxième exigence su Ggests que vous voulez un Map, mais ComboboxModel est un ListModel, ce qui suggère que vous voulez être en mesure de récupérer efficacement des éléments par "index".

Je ne crois pas que l'une des collections standard puisse le faire pour vous aussi simplement que vous le souhaitez.Vous pouvez soit créer une carte, puis copier les valeurs dans un List/ComboboxModel distinct, ou vous pouvez utiliser quelque chose comme IndexedList (une implémentation de liste qui maintient une carte d'index).

0

J'utilise le code suivant:

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