【问题标题】:JComboBox setting label and valueJComboBox 设置标签和值
【发布时间】:2011-08-05 09:59:03
【问题描述】:

是否可以将值和标签设置为 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

【问题讨论】:

    标签: java swing jcombobox


    【解决方案1】:

    您可以将任何对象放入 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;
        }
    }
    

    【讨论】:

    • 拜托,能给我看一个完整的例子吗?我不明白如何将此对象放入 JComboBox...
    • @xdevel2000 只需创建一组这些对象并将其设置到组合框 ComboItem[] items = new ComboItem[]{new ComboItem("value1", "label1"),new ComboItem("value2 ", "标签2")}; JComboBox cb = new JComboBox(items);
    • @kleopatra:那么当一个对象的toString是“foo”,你想让它在combo中显示“bar”时怎么办?使用渲染器有效。但是如果你在组合中击中 B,它不会选择任何东西。如果您在组合中按 F,它会选择呈现为“条”的项目。这是不可接受的。这就是为什么我建议使用具有适当 toString 方法的包装对象。
    • 这个。这应该是公认的答案。它完美地解决了这个问题。只需添加一个 toString 方法,该方法返回您想要在组合中显示的内容,然后将对象本身添加到组合中。
    • 另见this blogpost,它证实了 JB Nizet 所说的。因此,基本上,如果您想在组合框中显示普通字符串,请使用接受的答案,或者使用自定义渲染器和自定义 KeySelectionManager
    【解决方案2】:

    这里有一个实用程序接口和类,可以很容易地让组合框使用不同的标签。而不是创建一个替换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);
        }
    
    }
    

    如您所见,ToStringListCellRendererToString 实现中获取自定义字符串,然后将其传递给原始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 实现,您可以轻松地国际化组合框,而无需更改值对象中的任何内容。

    【讨论】:

    • 好的,但是从最终的 ToString toString 的 toString 方法每次我用鼠标在组合框上时都会调用它。如何减少调用次数?
    • 不错的尝试,它几乎成功了,但是如果您尝试将它与通用版本的 JComboBox 一起使用,它将会失败。
    【解决方案3】:

    请给我一个完整的例子吗?

    Enum 的实例对此特别方便,因为toString()“返回此枚举常量的名称,如声明中所包含的那样。”

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 这会起作用,但会破坏基于组合项的 toString 的键盘导航。
      • @JB Nizet:然后键盘导航坏了;-) 解决方法是修复它,而不是在 toString 中进行肮脏的修改
      • @kleopatra: 键盘导航代码深深隐藏在 javax.swing.plaf.basic.BasicComboUI 一个不可访问的内部类中,除了重新实现并耦合它之外,没有简单的方法到渲染器,覆盖它。我同意你的原则,但是Swing这部分的设计让遵循这个原则非常非常痛苦。我认为重新定义 toString 并将其他所有内容(等于、hashCode)委托给被包装对象的通用包装对象是一个更好的解决方案。
      • hmm ... 它不使用组合的 KeySelectionManager 吗?
      • 已选中:用户界面查询 combo.selectWithKey 反过来委托给它的 KeySelectionManager。因此,干净的解决方案是设置一个表现良好的管理器实现(即尊重实际字符串代表的实现)。刚刚注意到:SwingX 也有一个,但是忘记安装一个自定义管理器,它知道我们的 StringValue :-) 感谢您提出这个问题!
      【解决方案5】:

      第 1 步JComboBox,id,name这两个属性创建一个类,例如

      public class Product {
          private int id;
          private String name;
      
      
          public Product(){
      
          }
      
          public Product(int id, String name){        
              this.id = id;
              this.name = name;
          }
      
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
          //this method return the value to show in the JComboBox
          @Override
          public String toString(){
             return name;
          }
      
      }
      

      第 2 步 在表单的设计中,右键单击JComboBox并选择属性,现在打开代码选项卡并在属性类型参数中写入类的名称,在我们的示例中为产品。

      第 3 步 现在创建一个通过查询连接到数据库以生成产品列表的方法,该方法接收JComboBox 对象作为参数。

      public void showProducts(JComboBox <Product> comboProduct){
          ResultSet res = null;
          try {
              Connection conn = new Connection();
              String query = "select id, name from products";
              PreparedStatement ps = conn.getConecction().prepareStatement(query);
              res = ps.executeQuery();
              while (res.next()) {
                  comboProduct.addItem(new Product(res.getInt("id"), res.getString("name")));
              }
              res.close();
          } catch (SQLException e) {
              System.err.println("Error showing the products " + e.getMessage());
          }
      
      }
      

      第 4 步 您可以从表单中调用方法

      public frm_products() {
          initComponents();
      
          Product product = new Product(); 
      
          product.showProducts(this.cbo_product);
      
      }
      

      现在您可以使用getItemAt 方法访问选定的ID

      System.out.println(cbo_product.getItemAt(this.cbo_product.getSelectedIndex()).getId());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多