Требуется гибкий класс сбора ключей / значений Java для JComboBox - PullRequest
1 голос
/ 19 января 2010

У меня есть класс модели, в котором хранятся ключи и значения:

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 можно использовать для заполнения модели 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.

Помощь очень ценится.

Ответы [ 6 ]

3 голосов
/ 21 января 2010

Вы можете использовать пользовательский класс, подобный этому (запустить основную функцию, чтобы увидеть его поведение):

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

1 голос
/ 19 января 2010

Ваше второе требование предполагает, что вы хотите Карта , но ComboboxModel - это ListModel , которая предполагает, что вы захотите иметь возможность эффективно извлекать элементы по «индексу».

Я не верю, что какая-либо из стандартных коллекций может сделать это для вас так просто, как вам бы того хотелось. Вы можете либо создать карту, а затем скопировать значения в отдельную List / ComboboxModel, либо использовать что-то вроде IndexedList (реализация List, поддерживающая индексную карту).

1 голос
/ 19 января 2010

А как насчет java.util.Map реализаций?

с HashMap, например, вы можете иметь:

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

Однако вы не можете напрямую заполнить JComboBox Map. Вы можете добавить все ключи к JComboBox, а затем получить соответствующие значения при необходимости. Добавление может быть сделано многими способами, два из которых:

  • new JComboBox(map.keySet().toArray(new Object[]));
  • по петле:

    for (Object key : map.keySet() {
        comboBox.addItem(key);
    }
    
1 голос
/ 19 января 2010

Карта (реализация HashMap) является классом Key-Value.

Преобразовывает из ключа в значение с помощью метода # get.

Существует также метод для доступа ко всем ключам, всеценности и так далее.Так что у вас не должно возникнуть проблем с заполнением им модели.

Она также содержит пару ключ-значение, которая называется Map.Entry.

0 голосов
/ 12 февраля 2012

Я использую следующий код:

/**
 * This class is slightly modified version of the Pair class from this thread:
 * /122603/chto-ekvivalentno-pare-c-l-r-v-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 $
0 голосов
/ 19 января 2010

Я думаю, что простая 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...