有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java快速替代JComboBox/BasicComboxUI?

我有一个JComboBox可能有数千个项目。它们被分类了,并且在你输入的时候有find,所以原则上它不是完全不可用的

实际上,只有几百件物品是无法使用的。我使用setPrototypeDisplayValue()设法提高了初始显示性能,但是BasicListUI仍然坚持为框中的每个项目配置列表单元格呈现器(请参见BasicListUI.updateLayoutState()

这个,或者类似的东西,显然是对太阳的一个known issue;这已经持续了八年了,所以我不会屏息以待

除了实现我自己的UI之外,还有人有解决办法吗


共 (2) 个答案

  1. # 1 楼答案

    这是我想出的方法。缺点是:

    • 如果您想保持外观,就必须分别为您关心的每个BasicComboBoxUI扩展子类
    • 必须使用反射来加载UI类,因为(例如,WindowsComboBoxUI的子类不会在Linux上加载
    • 这对L&;Fs(例如MacOS?)不扩展BasicComboBoxUI
    • 它对ListCellRenderer做出的假设可能并不总是合理的

    我仍然对更清洁的解决方案持开放态度

    class FastBasicComboBoxUI extends BasicComboBoxUI {
      @Override
      public void installUI(JComponent c) {
        super.installUI(c);
    
        Object prototypeValue = this.comboBox.getPrototypeDisplayValue();
        if (prototypeValue != null) {
          ListCellRenderer renderer = comboBox.getRenderer();
          Component rendererComponent = renderer
              .getListCellRendererComponent(this.listBox, 
                  prototypeValue, 0, false, false);
          if (rendererComponent instanceof JLabel) {
            // Preferred size of the renderer itself is (-1,-1) at this point, 
            // so we need this hack
            Dimension prototypeSize = new JLabel(((JLabel) rendererComponent)
                .getText()).getPreferredSize();
            this.listBox.setFixedCellHeight(prototypeSize.height);
            this.listBox.setFixedCellWidth(prototypeSize.width);
          }
        }
      }
    }
    

    我仍然对更清洁的解决方案持开放态度

    以后

    事实证明,这只解决了部分问题。包含大量项目的组合框的初始显示可能仍然非常慢。我必须确保弹出列表框立即获得固定的单元格大小,方法是将代码移动到ComboPopup本身,如下所示。请注意,如上所述,这取决于原型值

    @Override
    protected ComboPopup createPopup() {
      return new BasicComboPopup(comboBox) {
        @Override
        protected JList createList() {
          JList list = super.createList();
          Object prototypeValue = comboBox.getPrototypeDisplayValue();
          if (prototypeValue != null) {
            ListCellRenderer renderer = comboBox.getRenderer();
            Component rendererComponent = renderer
                .getListCellRendererComponent(list, prototypeValue, 0, false, false);
            if (rendererComponent instanceof JLabel) {
              // Preferred size of the renderer itself is (-1,-1) at this point, 
              // so we need this hack
              Dimension prototypeSize = new JLabel(((JLabel) rendererComponent)
                  .getText()).getPreferredSize();
              list.setFixedCellHeight(prototypeSize.height);
              list.setFixedCellWidth(prototypeSize.width);
            }
          }
          return list;
        }
      };
    }
    
  2. # 2 楼答案

    ^{}可能是一个更好的选择,因为它使用了轻量级的渲染方法,并且似乎支持在键入时查找

    如果使用^{},在组件本身开始监听之前,向模型添加条目。这个SortedComboBoxModel使用了一个简单的insertion sort,可以接受几千个条目:

    class SortedComboBoxModel extends DefaultComboBoxModel {
    
        /** Add elements by inserting in lexical order. */
        @Override
        public void addElement(Object element) {
            this.insertElementAt(element, 0);
        }
    
        /** Insert in lexical order by name; ignore index. */
        @Override
        public void insertElementAt(Object element, int index) {
            String name = element.toString();
            for (index = 0; index < this.getSize(); index++) {
                String s = getElementAt(index).toString();
                if (s.compareTo(name) > 0) {
                    break;
                }
            }
            super.insertElementAt(element, index);
        }
    }