JavaFx TreeTableCell宽度计算
在我的应用程序中,我显示了一个TreeTableView,并希望增加缩进。我找到了相应的CSS属性JavaFx TreeTableCell宽度计算,javafx,javafx-8,openjdk,openjfx,Javafx,Javafx 8,Openjdk,Openjfx,在我的应用程序中,我显示了一个TreeTableView,并希望增加缩进。我找到了相应的CSS属性-fx indent,它工作得非常好。 然而,我现在正在努力计算首选宽度。 我希望专栏能够完美地包装它的内容,并使用中描述的反射来实现这一点 这可以使用默认缩进,但它似乎没有在计算中包含我的更改。通过挖掘源代码,我在TreeTableCellSkin类中发现了以下snippent: if (isDeferToParentForPrefWidth) { // RT-27167: we
-fx indent
,它工作得非常好。
然而,我现在正在努力计算首选宽度。
我希望专栏能够完美地包装它的内容,并使用中描述的反射来实现这一点
这可以使用默认缩进,但它似乎没有在计算中包含我的更改。通过挖掘源代码,我在TreeTableCellSkin
类中发现了以下snippent:
if (isDeferToParentForPrefWidth) {
// RT-27167: we must take into account the disclosure node and the
// indentation (which is not taken into account by the LabeledSkinBase.
return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);
}
return columnWidthProperty().get();
EDIT:我部分回答了前面的问题,发现此注释错误地存在,因为代码被移动到同一类中的leftLabelPadding()
方法:
// RT-27167: we must take into account the disclosure node and the
// indentation (which is not taken into account by the LabeledSkinBase.
...
double indentPerLevel = 10;
if (treeTableRow.getSkin() instanceof TreeTableRowSkin) {
indentPerLevel = ((TreeTableRowSkin<?>)treeTableRow.getSkin()).getIndentationPerLevel();
}
leftPadding += nodeLevel * indentPerLevel;
...
//RT-27167:我们必须考虑披露节点和
//缩进(LabeledSkinBase未考虑到这一点)。
...
双缩进水平=10;
if(treeTableRow.getSkin()实例为TreeTableRowSkin){
indentPerLevel=((TreeTableRowSkin)treeTableRow.getSkin()).getIndentationPerLevel();
}
leftPadding+=nodeLevel*indentPerLevel;
...
调试器显示,代码段可以工作,并在填充中添加了增加的缩进,但是单元格的宽度保持不变,并且我的文本溢出
你对在哪里或如何解决这个问题有什么想法吗?任何方向的提示都将不胜感激
非常感谢您!编辑
看起来问题已经用fx9解决了,所以下面的解决方案只对fx8是必要的(也是可能的)
/EDIT
好吧,我做了一些进一步的挖掘,找到了一个(希望是正确的)解释和一个肮脏的问题解决方案。对解释感兴趣的人可以在这篇文章的后面进一步阅读,因为这里所有其他人都是我肮脏的快速修复
肮脏但有效的解决方案:
Method fitColumn = TreeTableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TreeTableColumn.class, int.class);
fitColumn.setAccessible(true);
List<TreeTableColumn<S, ?>> tableColumns = aTreeTableView.getColumns();
for (TreeTableColumn<S, ?> treeTableColumn : aTreeTableView.getColumns()) {
fitColumn.invoke(aTreeTableView.getSkin(), treeTableColumn, -1);
/*
* FX does not include the altered indentation in the calculation for the prefWidth.
* Instead it uses a fixed constant of 10 (TreeTableCellSkin.leftLabelPadding()).
* To ensure the column can still display all its contents the remaining indentation must be added manually.
* To achieve this the maximum depth of the displayed tree is calculated and multiplied with the remaining indentation per level.
*/
TreeItem<S> rootItem = aTreeTableView.getRoot();
Stack<TreeItem<S>> items = new Stack<>();
if (aTreeTableView.isShowRoot() && rootItem != null) {
items.push(rootItem);
} else if (rootItem != null) {
rootItem.getChildren().forEach(items::push);
}
int maxLevel = -1;
while (!items.isEmpty()) {
TreeItem<S> curItem = items.pop();
int curLevel = aTreeTableView.getTreeItemLevel(curItem);
maxLevel = Math.max(curLevel, maxLevel);
if (curItem.isExpanded()) {
curItem.getChildren().forEach(items::push);
}
}
if (maxLevel >= 0) {
double indentation = 20; // the indentation used in the css stylesheet
double additionalIndentPerLevel = indentation - 10; // constant from TreeTableCellSkin
treeTableColumn.setPrefWidth(treeTableColumn.getWidth() + maxLevel * additionalIndentPerLevel);
}
同时,TreeTableCellSkin
类使用与单元格关联的TableRowSkin
来确定缩进:
// RT-27167: we must take into account the disclosure node and the
// indentation (which is not taken into account by the LabeledSkinBase.
...
double indentPerLevel = 10;
if (treeTableRow.getSkin() instanceof TreeTableRowSkin) {
indentPerLevel = ((TreeTableRowSkin<?>)treeTableRow.getSkin()).getIndentationPerLevel();
}
leftPadding += nodeLevel * indentPerLevel;
...
+1对于漂亮的挖掘和大胆的解决方案:)顺便说一句,我怀疑instanceof check失败是因为行没有皮肤(它从未添加到任何地方)。请注意,在fx9中,方法resizeColumnToFitContent移动到包私有类的静态实用程序方法中,无法访问…是的,这可能是原因。。。感谢您对fx9的建议。。我曾希望该方法能通过fx9应用于公共API,但当我在任何地方都找不到它时,我感到非常惊讶……我们都是乐观主义者,不是吗?即使总是一次又一次地失望;)刚刚检查了fx9:自定义缩进(通过-fx缩进定义)似乎按照预期工作,看起来bug已经修复好了,必须有人保持希望:)感谢快速跟进,我在fx9中编辑了一条关于bug修复的注释,并编辑了答案
TreeTableCell<S,?> cell = (TreeTableCell) cellFactory.call(col);
...
TreeTableRow<S> treeTableRow = new TreeTableRow<>();
treeTableRow.updateTreeTableView(treeTableView);
...
getChildren().add(cell);
cell.applyCss();
double w = cell.prefWidth(-1);
maxWidth = Math.max(maxWidth, w);
getChildren().remove(cell);
...
// RT-27167: we must take into account the disclosure node and the
// indentation (which is not taken into account by the LabeledSkinBase.
...
double indentPerLevel = 10;
if (treeTableRow.getSkin() instanceof TreeTableRowSkin) {
indentPerLevel = ((TreeTableRowSkin<?>)treeTableRow.getSkin()).getIndentationPerLevel();
}
leftPadding += nodeLevel * indentPerLevel;
...
TreeItem<S> rootItem = aTreeTableView.getRoot();
Stack<TreeItem<S>> items = new Stack<>();
if (aTreeTableView.isShowRoot() && rootItem != null) {
items.push(rootItem);
} else if (rootItem != null) {
rootItem.getChildren().forEach(items::push);
}
int maxLevel = -1;
while (!items.isEmpty()) {
TreeItem<S> curItem = items.pop();
int curLevel = aTreeTableView.getTreeItemLevel(curItem);
maxLevel = Math.max(curLevel, maxLevel);
if (curItem.isExpanded()) {
curItem.getChildren().forEach(items::push);
}
}
if (maxLevel >= 0) {
double indentation = 20; // the indentation used in the css stylesheet
double additionalIndentPerLevel = indentation - 10; // constant from TreeTableCellSkin
treeTableColumn.setPrefWidth(treeTableColumn.getWidth() + maxLevel * additionalIndentPerLevel);
}