【问题标题】:Nulls In JComboBox Stopping Arrow Key UseJComboBox 中的空值停止使用箭头键
【发布时间】:2011-01-21 10:52:38
【问题描述】:

下面的代码有一个错误。加载 JFrame 后,按 Tab 键将焦点放在 JComboBox 上,然后尝试按向下键。它什么也没做。

在位置 0 插入 Null 会导致这种情况。但是,我仍然希望能够选择 Null。我不想强迫用户选择一个选项。

package kobalt.test.colin;

import java.awt.*;
import javax.swing.*;

public class ColinTest extends JFrame {

    private JTextField mTextField;
    private JComboBox  mComboBox;

    public ColinTest(){
      setLayout(new BorderLayout());

      mTextField = new JTextField("Something");
      mComboBox = new JComboBox(new String[]{"One", "Two"});
      mComboBox.insertItemAt(null, 0); //this line causes the bug

      add(mTextField, "North");
      add(mComboBox, "South");

      pack();
      setVisible(true);
    }


    public static void main(String[] argv) {
      new ColinTest();
    }
}

我可以在 JComboBox 中覆盖什么来解决此问题吗?

我真的不喜欢在位置 0 处插入一个空字符串,因为我必须在任何地方处理它。

使用 Wrapping 对象可能是一种选择,但我宁愿扩展然后覆盖 JComboBox 中的某些内容。

【问题讨论】:

    标签: java swing jcombobox


    【解决方案1】:

    Null 对象在 JComboBox 中不能很好地发挥作用。例如,组合框的getSelectedIndex 方法(在您选择项目时触发)如果对象为null,则将返回-1。也可能有其他方法执行空检查并可能返回不正确的结果。

    但是您可以尝试覆盖 getSelectedIndex,以便在对象为空时返回 0 而不是 -1。还要覆盖selectedItemChanged,这样它就不会检查空值。以下似乎可行,但可能还有其他方法也需要覆盖:

    JComboBox mComboBox = new JComboBox(new String[]{"One", "Two"}){
        @Override
        public int getSelectedIndex() {
            Object sObject = dataModel.getSelectedItem();
            int i,c;
            Object obj;
    
            if(sObject==null){
                return 0;
            }
            for ( i=0,c=dataModel.getSize();i<c;i++ ) {
                obj = dataModel.getElementAt(i);
    
                 if ( obj != null && obj.equals(sObject) )
                    return i;
            }
            return -1;
        }
    
        @Override
        protected void selectedItemChanged() {
            fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
                    selectedItemReminder,
                    ItemEvent.DESELECTED));
            selectedItemReminder = dataModel.getSelectedItem();
    
            fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
                    selectedItemReminder,
                    ItemEvent.SELECTED));
        }
    };
    

    但是,我建议使用包装对象,而不是执行上述操作。例如:

    class StringWrapper{
        final String s;
        public StringWrapper(String s){
            this.s=s;
        }
        @Override
        public String toString() {
            return s;
        }
    }
    
    JComboBox cb = new JComboBox(new StringWrapper[]{ 
                new StringWrapper("one"),
                new StringWrapper("two"),
                new StringWrapper("three")});
    cb.insertItemAt(new StringWrapper(null), 0); 
    

    【讨论】:

    • 我使用了一个包装对象,谢谢。我不喜欢“可能还有其他方法也需要重写”这句话:)
    【解决方案2】:

    以这种方式创建组合框会创建基于 Vector 的 DefaultComboBoxModel。所以不能插入空值。您可以尝试使用空值支持来实现您的 ComboBoxModel。

    【讨论】:

    • -1 这是错误的。可以将空值插入模型中。如果元素为空,组合框的行为会有所不同。