2011-04-14 287 views
11

是否有可能设置一个值和标签的JComboBox这样我就可以显示出一个标签,但得到的值是不同的?的JComboBox设置标签和值

例如在JavaScript中我可以这样做:

document.getElementById("myselect").options[0].value //accesses value attribute of 1st option 
document.getElementById("myselect").options[0].text //accesses text of 1st option 

回答

1

使用ListCellRenderer达到你想要的东西。创建一个延伸JLabel的类并实现ListCellRenderer。使用setRenderer()方法将该类设置为JComboBox中的渲染器。现在,当你从你的jcombobox访问值时,它将是jlabel类型的。

+1

这将工作,但会打破键盘导航,这是基于组合项目的toString。 – 2011-04-14 10:12:18

+0

@JB Nizet:那么键盘导航是坏的;-)要走的方法是解决它而不是肮脏的黑客在toString – kleopatra 2011-04-15 12:46:18

+0

@kleopatra:键盘导航代码深藏在javax.swing的一个不可访问的内部类中.plaf.basic.BasicComboUI,除了重新实现它并将其与渲染器耦合,并没有简单的方法来覆盖它。我同意你的原则,但这部分Swing的设计使得遵循这个原则非常痛苦。我认为一个通用的包装器对象重新定义toString并委托一切(equals,hashCode)包装对象是一个更好的解决方案。 – 2011-04-15 14:26:17

25

你可以把任何物体的JComboBox内。默认情况下,它使用对象的toString方法显示标签,使用键盘在组合框中导航。所以,最好的办法可能是定义和使用组合中适当的对象:

public class ComboItem { 
    private String value; 
    private String label; 

    public ComboItem(String value, String label) { 
     this.value = value; 
     this.label = label; 
    } 

    public String getValue() { 
     return this.value; 
    } 

    public String getLabel() { 
     return this.label; 
    } 

    @Override 
    public String toString() { 
     return label; 
    } 
} 
+0

请给我看一个完整的例子吗?我不'理解如何把这个对象放入一个JComboBox中...... – xdevel2000 2011-04-14 10:40:32

+2

@ xdevel2000只需创建一个这些对象的aray并将其设置为ComboItem [] items = new ComboItem [] {new ComboItem(“value1”, “label1”),新的ComboItem(“value2”,“label2”)}; JComboBox cb = new JComboBox(items); – Boro 2011-04-14 11:23:54

+2

@kleopatra:那么当对象的toString是“foo”,并且你想让它在组合中显示“bar”时,你会怎么做?使用渲染器的作品。但是如果你在组合中击中B,它不会选择任何东西。如果您在组合中按F,它会选择渲染为“酒吧”的项目。这是不可接受的。这就是为什么我建议使用具有足够的toString方法的包装对象。 – 2011-04-15 14:17:44

6

,能不能请给我一个完整的例子吗?的Enum

实例是用于该特别方便,因为toString()“返回该枚举常数的名称,它包含在声明”。

enter image description here

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

/** @see http://stackoverflow.com/questions/5661556 */ 
public class ColorCombo extends JPanel { 

    private Hue hue = Hue.values()[0]; 

    public ColorCombo() { 
     this.setPreferredSize(new Dimension(320, 240)); 
     this.setBackground(hue.getColor()); 
     final JComboBox colorBox = new JComboBox(); 
     for (Hue h : Hue.values()) { 
      colorBox.addItem(h); 
     } 
     colorBox.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       Hue h = (Hue) colorBox.getSelectedItem(); 
       ColorCombo.this.setBackground(h.getColor()); 
      } 
     }); 
     this.add(colorBox); 
    } 

    private enum Hue { 

     Cyan(Color.cyan), Magenta(Color.magenta), Yellow(Color.yellow), 
     Red(Color.red), Green(Color.green), Blue(Color.blue); 

     private final Color color; 

     private Hue(Color color) { 
      this.color = color; 
     } 

     public Color getColor() { 
      return color; 
     } 
    } 

    private static void display() { 
     JFrame f = new JFrame("Color"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(new ColorCombo()); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       display(); 
      } 
     }); 
    } 
} 
8

这里有一个公用设施接口和类,它可以很容易地得到一个组合框使用不同的标签。而不是创建一个替代品ListCellRenderer(并且如果外观变化时冒着不适当的风险),它会使用默认的ListCellRenderer(不管可能如何),但是将自己的字符串换成标签文本而不是那些在您的值对象中由toString()定义。

public interface ToString { 
    public String toString(Object object); 
} 

public final class ToStringListCellRenderer implements ListCellRenderer { 
    private final ListCellRenderer originalRenderer; 
    private final ToString toString; 

    public ToStringListCellRenderer(final ListCellRenderer originalRenderer, 
      final ToString toString) { 
     this.originalRenderer = originalRenderer; 
     this.toString = toString; 
    } 

    public Component getListCellRendererComponent(final JList list, 
      final Object value, final int index, final boolean isSelected, 
      final boolean cellHasFocus) { 
     return originalRenderer.getListCellRendererComponent(list, 
      toString.toString(value), index, isSelected, cellHasFocus); 
    } 

} 

正如你可以看到ToStringListCellRenderer获得从ToString实现自定义字符串,然后把它传递给原ListCellRenderer强似在值对象本身。

若要使用此代码,这样做如下:

// Create your combo box as normal, passing in the array of values. 
final JComboBox combo = new JComboBox(values); 
final ToString toString = new ToString() { 
    public String toString(final Object object) { 
     final YourValue value = (YourValue) object; 
     // Of course you'd make your own label text below. 
     return "custom label text " + value.toString(); 
    } 
}; 
combo.setRenderer(new ToStringListCellRenderer(
     combo.getRenderer(), toString))); 

除了使用该制作自定义标签,如果你犯了一个ToString实现创建基于系统区域设置字符串,就可以轻松国际化组合框,而不必改变你的价值对象中的任何东西。

+0

好的,但toString方法从最终的ToString toString每次当我用鼠标在comboBox上时调用它。如何减少调用次数? – Blocked 2014-05-10 11:08:31