我有JComboBox
可能有数千件物品。它们是有序的,并且有找到你的类型,所以原则上它并不完全无法使用。
在实践中,只有几百个项目它几乎无法使用。我设法使用setPrototypeDisplayValue()
改善了初始显示效果,但BasicListUI
仍然坚持为框中的每个项目配置列表单元格渲染器(请参阅BasicListUI.updateLayoutState()
)。
这个,或类似的东西,显然是太阳的known issue;现在已经八年了,所以我不会屏住呼吸。
如果没有实施我自己的用户界面,有没有人有解决方法?
答案 0 :(得分:2)
JList
可能是更好的选择,因为它使用了飞行重量方法进行渲染,并且似乎支持“按类型查找”。
如果您使用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);
}
}
答案 1 :(得分:0)
这是我提出的黑客行为。缺点是:
BasicComboBoxUI
扩展名WindowsComboBoxUI
的子类不会在Linux上加载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;
}
};
}