基本上,问题有两个方面,都位于ui委托中
>测量时无法将渲染器配置为其实际状态,这完全忽略了选择(和焦点)
>众所周知,对于被迫重新计算缓存的单元格大小是非常顽固的:它没有公开的api这样做,只能自愿进行模型更改.
解决第一个问题的方法确实是渲染器:实现忽略给定的选定标志并查询列表中的实际选择,如@Andy所述.在代码中,使用OP的组件
ListCellRenderer renderer = new ListCellRenderer() {
Yeah yeah = new Yeah(false);
Oh oh = new Oh();
@Override
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected,
boolean cellHasFocus) {
// ignore the given selection index, query the list instead
if (list != null) {
isSelected = list.isSelectedIndex(index);
}
if (isSelected || ((Integer) value) == 42) {
yeah.isSelected = isSelected;
return yeah;
}
return oh;
}
};
list.setCellRenderer(renderer);
要修复第二个问题,自定义ui委托(也可以在其他人的答案中建议)是一种可能的解决方案.虽然有些工作在一般情况下,但是如果需要支持多个LAF.
强制ui自动更新其缓存的一种不那么干扰但稍微脏的方法是在selectionChange上发送一个假的ListDataEvent:
ListSelectionListener l = new ListSelectionListener() {
ListDataEvent fake = new ListDataEvent(list, ListDataEvent.CONTENTS_CHANGED, -1, -1);
@Override
public void valueChanged(ListSelectionEvent e) {
JList list = (JList) e.getSource();
ListDataListener[] listeners = ((AbstractListModel) list.getModel())
.getListDataListeners();
for (ListDataListener l : listeners) {
if (l.getClass().getName().contains("ListUI")) {
l.contentsChanged(fake);
break;
}
}
}
};
list.addListSelectionListener(l);
BTW,SwingX项目的JXList有一个自定义ui委托 – 主要用于支持排序/过滤 – 用公共api重新计算缓存,然后上面的ListSelectionListener将被简化(并且干净:-)到
ListSelectionListener l = new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
((JXList) e.getSource()).invalidateCellSizeCache();
}
};
list.addListSelectionListener(l);