问题描述
我有一个JComboBox
,它可能具有数千个项目.它们经过排序,并且可以按需输入,因此从原则上讲,它并不是完全不可用的.
I've got a JComboBox
that potentially can have thousands of items. They're sorted, and there's find-as-you-type, so in principle it's not completely unusable.
在实践中,仅使用几百个项目就无法使用.我设法使用setPrototypeDisplayValue()
改善了初始显示性能,但是BasicListUI
仍然坚持为框中的每个项目配置列表单元格渲染器(请参见BasicListUI.updateLayoutState()
).
In practice, it's pretty unusable with just a couple of hundred items. I managed to improve the initial display performance using setPrototypeDisplayValue()
, but BasicListUI
still insists on configuring the list cell renderer for every item in the box (see BasicListUI.updateLayoutState()
).
这个或类似的东西显然是一个已知问题到太阳;已经过去八年了,所以我没有屏住呼吸.
This, or something like it, is apparently a known issue to Sun; it has been for going on eight years now, so I'm not holding my breath.
实现我自己的UI的捷径,有人解决过吗?
Short of implementing my own UI, has anyone got a workaround?
推荐答案
这是我想到的技巧.缺点是:
Here's the hack that I came up with. The drawbacks are:
- 如果要保持外观,则必须分别关注每个
BasicComboBoxUI
扩展名的子类 - 您必须使用反射来加载UI类,因为(例如)
WindowsComboBoxUI
的子类在Linux上不会加载 - 它不能与不扩展
BasicComboBoxUI
的L& F(例如MacOS?)一起使用 - 它对
ListCellRenderer
做出的假设可能并不总是必要的
- if you want to maintain the look and feel, you have to separately subclass each
BasicComboBoxUI
extension you care about - you have to use reflection to load your UI classes, since (for instance) a subclass of
WindowsComboBoxUI
won't load on Linux - it won't work with L&Fs (e.g. MacOS?) that don't extend
BasicComboBoxUI
- it makes assumptions about the
ListCellRenderer
that may not always be warranted
我仍然对清洁的解决方案持开放态度.
I'm still open to cleaner solutions.
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);
}
}
}
}
我仍然对清洁的解决方案持开放态度.
I'm still open to cleaner solutions.
稍后
结果证明这只能解决部分问题.带有大量项目的组合框的初始显示可能仍然很慢.我必须通过将代码移到ComboPopup
本身中来确保弹出列表框立即获得固定的单元格大小,如下所示.请注意,如上所述,这取决于原型值.
Turns out this only solved some of the problems. Initial display of a combo box with a large number of items could still be really slow. I had to make sure the popup list box immediately gets a fixed cell size, by moving the code into the ComboPopup
itself, as follows. Note that, as above, this depends on the prototype value.
@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;
}
};
}
这篇关于是否可以快速替换JComboBox/BasicComboBoxUI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!