JavaFx TreeTableCell宽度计算

JavaFx TreeTableCell宽度计算,javafx,javafx-8,openjdk,openjfx,Javafx,Javafx 8,Openjdk,Openjfx,在我的应用程序中,我显示了一个TreeTableView,并希望增加缩进。我找到了相应的CSS属性-fx indent,它工作得非常好。 然而,我现在正在努力计算首选宽度。 我希望专栏能够完美地包装它的内容,并使用中描述的反射来实现这一点 这可以使用默认缩进,但它似乎没有在计算中包含我的更改。通过挖掘源代码,我在TreeTableCellSkin类中发现了以下snippent: if (isDeferToParentForPrefWidth) { // RT-27167: we

在我的应用程序中,我显示了一个TreeTableView,并希望增加缩进。我找到了相应的CSS属性
-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);
}