2010-07-07 79 views
2

我有一个JComboBox可能可以有数千个项目。它们被排序,并且有即发型,所以原则上它不是完全无法使用的。快速替换JComboBox/BasicComboBoxUI?

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

这个或类似的东西显然是Sun的known issue;现在已经过去八年了,所以我并没有屏住呼吸。

缺乏实施我自己的用户界面,有没有人有解决方法?

+6

在我的小见解中,除了表现之外,我会担心用户体验。如果组合框中可能有数千个项目,那么也许是时候尝试将它们分类(并有第二个组合框),或让另一个组件找到您的值。你有一个“找到你键入”的方法,也许你应该有一个专门的组件,从不显示整个列表,只有一个过滤视图。它也将解决性能问题。 – Gnoupi 2010-07-07 13:22:27

+1

@mcandre,如果我想要我的散文风格的建议,我不会来堆栈溢出。相同的JComboBox可能有一个项目或零。一个典型的数字是十。 “可能会有”不是多余的,它是准确的。 – 2010-07-08 07:16:22

回答

0

下面是我想出了破解。缺点是:

  • ,如果你想保持外观和感觉,你必须单独继承每个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

JList可能是一个更好的选择,因为它使用fly-weight方法来呈现,并且似乎支持按照您的类型查找。

如果您使用JComboBox,则在之前将组件添加到模型,组件本身开始侦听。这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); 
    } 
} 
+0

这不是真正的问题 - 该模型在组合框存在之前完全构建,并且对其进行更改是全有或全无。 – 2010-07-09 13:58:09