9

JComponents can obtain hidden data using setName() and getName(), right? What about JComboBox items? (I'm referring to the items in the JComboBox, NOT the JComboBox itself)

What if I have a JComboBox, and inside it I have a list of usernames (for example), now I want to have something like 'id' for each username in the list according to how they are ordered, what's the best way to do this?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
evilReiko
  • 19,501
  • 24
  • 86
  • 102

3 Answers3

13
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;

public class ComboBoxItem extends JFrame implements ActionListener
{
    public ComboBoxItem()
    {
        Vector model = new Vector();
        model.addElement( new Item(1, "car" ) );
        model.addElement( new Item(2, "plane" ) );
        model.addElement( new Item(3, "train" ) );
        model.addElement( new Item(4, "boat" ) );
        model.addElement( new Item(5, "boat aadf asfsdf a asd asd" ) );

        JComboBox comboBox;

        //  Easiest approach is to just override toString() method
        //  of the Item class

        comboBox = new JComboBox( model );
        comboBox.addActionListener( this );
        comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
        getContentPane().add(comboBox, BorderLayout.NORTH );

        //  Most flexible approach is to create a custom render
        //  to diplay the Item data

        comboBox = new JComboBox( model );
        comboBox.setRenderer( new ItemRenderer() );
        comboBox.addActionListener( this );
        getContentPane().add(comboBox, BorderLayout.SOUTH );
    }

    public void actionPerformed(ActionEvent e)
    {
        JComboBox comboBox = (JComboBox)e.getSource();
        Item item = (Item)comboBox.getSelectedItem();
        System.out.println( item.getId() + " : " + item.getDescription() );
    }

    class ItemRenderer extends BasicComboBoxRenderer
    {
        public Component getListCellRendererComponent(
            JList list, Object value, int index,
            boolean isSelected, boolean cellHasFocus)
        {
            super.getListCellRendererComponent(list, value, index,
                isSelected, cellHasFocus);

            if (value != null)
            {
                Item item = (Item)value;
                setText( item.getDescription().toUpperCase() );
            }

            if (index == -1)
            {
                Item item = (Item)value;
                setText( "" + item.getId() );
            }


            return this;
        }
    }

    class Item
    {
        private int id;
        private String description;

        public Item(int id, String description)
        {
            this.id = id;
            this.description = description;
        }

        public int getId()
        {
            return id;
        }

        public String getDescription()
        {
            return description;
        }

        public String toString()
        {
            return description;
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new ComboBoxItem();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible( true );
     }

}

Also check out: Combo Box With Hidden Data for more information on these approaches.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Thanks for the answer, really solved my problem :) but isn't it bad to use deprecated code "Vector"? Is there a way to avoid using Vectors? – evilReiko Mar 03 '11 at 10:05
  • 1
    Vector is not deprecated (at least in JDK6). Swing components use Models to store the data. The DefaultComboBoxModel uses a Vector to store the data. If you don't like this you can always create your own Model and use whatever you want to store the data. – camickr Mar 03 '11 at 16:10
5

Your object :

public class Item {

    private int id;
    private String name;

    public Item(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String toString(){
        return this.name;
    }
}

Add items to your JComboBox :

JComboBox combo;

combo.addItem(new Item(1, "Test"));
combo.addItem(new Item(15,"Test 2"));

And get Item :

Item selected_item = (Item) combo.getSelectedItem();

System.out.println(selected_item.getId());
System.out.println(selected_item.getName());
Akna
  • 139
  • 2
  • 6
  • 1
    overriding toString for the sake of showing in a JSomething is **not* the recommended way. See @camickr 's answer for the correct approach. – kleopatra Nov 01 '12 at 10:12
3

Create a User class which has the attributes username and id; return only username in .toString().

atamanroman
  • 11,607
  • 7
  • 57
  • 81
  • 1
    overriding toString for the sake of showing in a JSomething is **not* the recommended way. See @camickr 's answer for the correct approach. – kleopatra Nov 01 '12 at 10:13
  • 1
    it's not at all okay (except for the most trivials of applications) - you would end up with tens of Item variants which only vary in their respective toString implementation just because you want to render them differently in different contexts. In Swing there's a mechanism _designed_ to handle that variance, and that's a renderer. – kleopatra Nov 02 '12 at 10:12
  • nothing to do with doing something upfront - you are simply doing it _wrong_ in Swing-land ;-) You are free to believe otherwise, of course. – kleopatra Nov 02 '12 at 11:02
  • 1
    Don't fix what's not broken. Trivial question - trivial answer for trivial application. May not be very enterprisey. – atamanroman Nov 02 '12 at 11:12