正如我在评论中已经提到的,这是一个错误。问题是多方面的:
- 负责测量原型尺寸要求的代码是 ColumnFactory.calcPrototypeWidth
- 它通过使用给定原型配置表返回的渲染器并测量其 prefSize 来实现
- 使用黑魔法将分层列的呈现委托给 JTree
- 默认工厂不知道那个黑魔法,因此查询独立于原型的 JTree 的 prefSize
- 第一个想法:让工厂知道分层列的特殊渲染,然后走到真正的底层treeCellRenderer - 不起作用,再次由于其他一些内部黑魔法
- 由于设置原型而导致的自动列大小调整在 JXTable 中被破坏(问题 #1510)
解决方法涉及
- 一个自定义的 ColumnFactory,它知道分层列的特殊渲染器(== JXTree))
- 对于分层列,配置和测量 TreeCellRenderer - 不是树本身使用的,而是不相关的虚拟对象
- 设置原型后,手动触发列的大小评估
下面是一个自定义的 ColumnFactory 及其用法(未经正式测试,因此请谨慎使用 :-)。
// a custom factory
ColumnFactory factory = new ColumnFactory() {
@Override
protected int calcPrototypeWidth(JXTable table,
TableColumnExt columnExt) {
if (isHierarchicalPrototype(table, columnExt)) {
return calcHierarchicalPrototypeWidth((JXTreeTable) table, columnExt);
}
return super.calcPrototypeWidth(table, columnExt);
}
protected boolean isHierarchicalPrototype(JXTable table,
TableColumnExt columnExt) {
return (table instanceof JXTreeTable)
&& ((JXTreeTable) table).getTreeTableModel().getHierarchicalColumn() ==
columnExt.getModelIndex()
&& columnExt.getPrototypeValue() != null;
}
TreeCellRenderer dummy = new DefaultTreeCellRenderer();
protected int calcHierarchicalPrototypeWidth(JXTreeTable table,
TableColumnExt columnExt) {
JXTree renderer = (JXTree) getCellRenderer(table, columnExt);
// commented lines would be the obvious step down into the "real" sizing
// requirements, but giving reasonable result due to internal black magic
// TreeCellRenderer treeRenderer = renderer.getCellRenderer();
// Component comp = treeRenderer.getTreeCellRendererComponent(renderer,
columnExt.getPrototypeValue(), false, false, false, -1, false);
// instead, measure a dummy
Component comp = dummy.getTreeCellRendererComponent(renderer,
columnExt.getPrototypeValue(), false, false, false, -1, false);
return Math.max(renderer.getPreferredSize().width, comp.getPreferredSize().width);
}
};
// usage: first create the treeTable, set the factory and set the model
JXTreeTable table = new JXTreeTable();
table.setColumnFactory(factory);
table.setTreeTableModel(new FileSystemModel());
// set the prototype
table.getColumnExt(0).setPrototypeValue("long longer longest still not enough to really see" +
" some effect of the prototype if available");
// Issue #1510: prototype value handling broken in underlying JXTable
// need to manually force the config
table.getColumnFactory().configureColumnWidths(table, table.getColumnExt(0));