获取JavaFX中节点的高度(生成布局传递)

如何在JavaFX中获得节点的高度或者更喜欢高度,我有3个VBox ,我想将节点添加到最自由的面板,例如:

  Childrens Total Height of the children's(Sum) VBoxA 5 890 VBoxB 4 610 VBoxC 2 720 

在这种情况下,最自由的是VBoxB ,我用这种方法计算最自由的窗格:

 private int getFreerColumnIndex() { if(columns.isEmpty()) return -1; int columnIndex = 0; int minHeight = 0; for(int i = 0; i < columns.size(); i++) { int height = 0; for(Node n : columns.get(i).getChildren()) { height += n.getBoundsInLocal().getHeight(); } if(i == 0) { minHeight = height; } else if(height < minHeight) { minHeight = height; columnIndex = i; } if(height == 0) break; } return columnIndex; } 

此方法仅在我添加1个元素时才有效。 但是如果我当时添加更多元素:

 for (int i = 0; i < 10; i++) { SomeNode r1 = new SomeNode (); myPane.addElement(r1); } 

方法getFreerColumnIndex返回相同的索引。 这是因为新节点在本地还没有高度。
所以这一行:

 height += n.getBoundsInLocal().getHeight(); 

将使用新节点返回0

任何人都知道如何获得节点的高度?


额外:

SomeNode扩展了Node

myPane上的方法addElement():

 public void addElement(final Node element) { index = getFreerColumnIndex(); columns.get(index).getChildren().add(element); } 

额外2:

假设我们有3个vbox:之前:

  ABC | | | | | | 

跑:

 for (int i = 0; i < 10; i++) { SomeNode r1 = new SomeNode (); myPane.addElement(r1); } 

后:

  ABC | | | | | | | | | | | | | | | | 

正确

  ABC | | | | | | | | | | | | | | | | 

| =某个节点

你需要做的是:

  1. 创建要放置在VBox中的节点。
  2. 将它们添加到某个场景(它可能只是一个未附加到舞台但与主场景具有相同CSS规则的新虚拟场景)。
  3. 在每个节点(或虚拟场景根)上调用applyCss()layout() )。
  4. 测量每个节点的布局边界。
  5. 根据布局算法将节点添加到真实场景中的VBox。

有关

要了解如何测量节点的大小,请参阅以下答案:

  • 如何计算JavaFX中String的像素宽度?

背景

JavaFX布局计算通过应用CSS和布局传递来工作。 通常这是作为脉冲的一部分发生的(内部JavaFX系统中的一种自动60fps刻度,它检查场景中需要应用新css或布局的任何脏对象)。 在大多数情况下,您只需指定场景所需的更改,并让自动脉冲布局机制在此时处理布局; 这样做非常有效,因为这意味着脉冲之间的任何更改都会被批量处理,您不需要手动触发布局传递。 但是,当您需要在布局发生之前(例如在您的情况下)实际获取事物的大小时,您需要在尝试查询节点的高度和宽度范围之前手动触发CSS应用程序和布局传递。

文档

遗憾的是, node.applyCSS()方法的详细Java 8u20 Javadoc目前已被破坏,因此我将重现此处Javadoc代码中的示例,以便您可以在上下文中查看建议的用法。 对于下一个Javafunction版本(8u40),破坏的javadoc作为RT-38330的一部分被修复了。对于Node类的几个方法缺少Javadoc ,因此在该版本中,您将能够在JavaFX javadoc中找到以下文本:

如果需要,请将样式应用于此节点及其子节点(如果有)。 此方法通常不需要直接调用,但可以与layout()一起使用,以在下一个脉冲之前调整节点大小,或者如果场景不在舞台中。

如果Node的场景不为null,则无论此Node的CSS状态是否干净,都将CSS应用于此Node。 CSS样式从此Node的最顶层父节点应用,其CSS状态不是clean,这可能会影响其他节点的样式。 如果Node不在场景中,则此方法为无操作。 场景不必处于舞台中。

此方法不会调用layout()方法。 通常,调用者将使用以下操作序列。

 parentNode.applyCss(); parentNode.layout(); 

作为一个更完整的示例,以下代码使用applyCss()layout()在显示舞台之前查找Button的宽度和高度。 如果对applyCss()的调用或对layout()的调用被注释掉,则对getWidth()getHeight()的调用将返回零(直到显示Stage之后的某个时间)。

 public void start(Stage stage) throws Exception { Group root = new Group(); Scene scene = new Scene(root); Button button = new Button("Hello World"); root.getChildren().add(button); root.applyCss(); root.layout(); double width = button.getWidth(); double height = button.getHeight(); System.out.println(width + ", " + height); stage.setScene(scene); stage.show(); } 

替代

这里的另一个选项是覆盖父节点的layoutChildren()方法,即“在布局传递期间调用以布置此父节点中的子节点”。 在这样做时,可能还需要覆盖computePrefHeight()方法以及prefWidth和min&max height&width的其他计算方法。 使用这种方法的详细描述很复杂,超出了本答案的范围。