java 获取JavaFX中节点的高度(生成布局pass)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26152642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get the height of a node in JavaFX (generate a layout pass)
提问by iconer
How to get the height or prefer height of a node in JavaFX, I have 3 VBox
and I want to add nodes to the the most freer panel, example:
如何在 JavaFX 中获取节点的高度或偏好高度,我有 3 个VBox
,我想将节点添加到最自由的面板中,例如:
Childrens Total Height of the children's(Sum)
VBoxA 5 890
VBoxB 4 610
VBoxC 2 720
in this case, the most freer is the VBoxB
, I calculate the most freer pane with this method:
在这种情况下,最自由的是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;
}
This method only works if I add 1 element at the time. But if I add more elements at the time:
此方法仅在我当时添加 1 个元素时才有效。但是如果我当时添加更多元素:
for (int i = 0; i < 10; i++) {
SomeNode r1 = new SomeNode ();
myPane.addElement(r1);
}
the method getFreerColumnIndex
return the same index. This is because the new nodes dont have heigth in local yet.
So this line:
该方法getFreerColumnIndex
返回相同的索引。这是因为新节点在本地还没有 heigth。
所以这一行:
height += n.getBoundsInLocal().getHeight();
will return 0
with the new nodes.
将0
与新节点一起返回。
Anyone knows how to get the heigth of a node ?
任何人都知道如何获得节点的高度?
Extra:
额外的:
SomeNode
extends of Node
SomeNode
延伸的 Node
Method addElement() at myPane:
myPane 中的方法 addElement():
public void addElement(final Node element) {
index = getFreerColumnIndex();
columns.get(index).getChildren().add(element);
}
Extra 2:
额外2:
suppose we have 3 vbox: Before:
假设我们有 3 个 vbox: 之前:
A B C
| | |
| |
|
Run:
跑:
for (int i = 0; i < 10; i++) {
SomeNode r1 = new SomeNode ();
myPane.addElement(r1);
}
After:
后:
A B C
| | |
| | |
| |
|
|
|
|
|
|
|
|
Correct:
正确:
A B C
| | |
| | |
| | |
| | |
| | |
|
|
= Some node
|
= 某个节点
回答by jewelsea
What you need to do is:
你需要做的是:
- Create the nodes which are to be placed in the VBoxes.
- Add them to some scene (it can just be a new dummy scene not attached to the stage but having the same CSS rules as your main scene).
- Call
applyCss()
andlayout()
on each of the nodes (or the dummy scene root). - Measure the layout bounds of each of the nodes.
- Add the nodes to the VBoxes in your real scene according to your layout algorithm.
- 创建要放置在 VBox 中的节点。
- 将它们添加到某个场景中(它可以只是一个新的虚拟场景,不附加到舞台,但具有与主场景相同的 CSS 规则)。
- 在每个节点(或虚拟场景根)上调用
applyCss()
和layout()
。 - 测量每个节点的布局边界。
- 根据布局算法将节点添加到真实场景中的 VBox。
Related
有关的
To find out how to measure the size of a node, see the answer to:
要了解如何测量节点的大小,请参阅以下答案:
Background
背景
JavaFX layout calculations work by applying CSS and a layout pass. Normally this occurs as part of a pulse (a kind of automated 60fps tick in the internal JavaFX system which checks for any dirty objects in the scene which need new css or layout applied to them). In most cases, you can just specify the changes you want to the scene and let the automated pulse layout mechanism handle the layout at that time; doing so is quite efficient as it means that any changes between a pulse are batched up and you don't need to manually trigger layout passes. However, when you need to actually get the size of things before the layout occurs (as in your case), then you need to manually trigger the CSS application and layout pass before you try to query the height and width extents of the node.
JavaFX 布局计算通过应用 CSS 和布局传递来工作。通常,这作为脉冲的一部分发生(内部 JavaFX 系统中的一种自动 60fps 滴答声,用于检查场景中是否有任何需要应用新 css 或布局的脏对象)。大多数情况下,您只需指定您想要的场景更改,并让自动脉冲布局机制处理当时的布局;这样做非常有效,因为这意味着脉冲之间的任何更改都会被批量处理,您无需手动触发布局传递。但是,当您需要在布局发生之前实际获取事物的大小时(如您的情况),那么您需要在尝试查询节点的高度和宽度范围之前手动触发 CSS 应用程序和布局传递。
Documentation
文档
Unfortunately the detailed Java 8u20 Javadoc for the node.applyCSS()
method is currently broken, so I'll reproduce the sample which is in the Javadoc code here, so you can see the recommended usage in context. For the next Java feature release (8u40), the broken javadoc is fixed as part of RT-38330 Javadoc is missing for several methods of the Node class, so with that release, you will be able to find the following text in the JavaFX javadoc:
不幸的是,该node.applyCSS()
方法的详细 Java 8u20 Javadoc当前已损坏,因此我将在此处重现 Javadoc 代码中的示例,以便您可以在上下文中查看推荐的用法。对于下一个 Java 功能版本 (8u40),损坏的 javadoc 已修复为RT-38330 的一部分Javadoc 缺少 Node 类的几个方法,因此在该版本中,您将能够在 JavaFX javadoc 中找到以下文本:
If required, apply styles to this Node and its children, if any. This method does not normally need to be invoked directly but may be used in conjunction with
layout()
to size a Node before the next pulse, or if the Scene is not in a Stage.Provided that the Node's Scene is not null, CSS is applied to this Node regardless of whether this Node's CSS state is clean. CSS styles are applied from the topmost parent of this Node whose CSS state is other than clean, which may affect the styling of other nodes. This method is a no-op if the Node is not in a Scene. The Scene does not have to be in a Stage.
This method does not invoke the
layout()
method. Typically, the caller will use the following sequence of operations.parentNode.applyCss(); parentNode.layout();
As a more complete example, the following code uses
applyCss()
andlayout()
to find the width and height of the Button before the Stage has been shown. If either the call toapplyCss()
or the call tolayout()
is commented out, the calls togetWidth()
andgetHeight()
will return zero (until some time after the Stage is shown).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(); }
如果需要,将样式应用到此节点及其子节点(如果有)。此方法通常不需要直接调用,但可以结合使用
layout()
以在下一个脉冲之前确定节点的大小,或者如果场景不在舞台中。如果节点的场景不为空,则无论此节点的 CSS 状态是否为干净,都将 CSS 应用于此节点。CSS 样式是从该节点的最顶层父节点应用的,其 CSS 状态不是干净的,这可能会影响其他节点的样式。如果节点不在场景中,则此方法无操作。场景不必在舞台中。
此方法不调用该
layout()
方法。通常,调用者将使用以下操作序列。parentNode.applyCss(); parentNode.layout();
作为一个更完整的示例,以下代码使用
applyCss()
和layout()
来在显示舞台之前查找 Button 的宽度和高度。如果注释掉调用 toapplyCss()
或调用 tolayout()
,则调用getWidth()
和getHeight()
将返回零(直到显示舞台后的某个时间)。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(); }
Alternative
选择
The other option here is to override the layoutChildren()
method of a parent node, which is "Invoked during the layout pass to layout the children in this Parent.". In doing so, it may also be necessary to override methods to computePrefHeight()
as well as other computation methods for prefWidth and min & max height & width. A detailed description of using this approach is complicated and outside the scope of this answer.
这里的另一个选项是覆盖layoutChildren()
父节点的方法,即“在布局传递期间调用以在此父节点中布局子节点。”。这样做时,可能还需要覆盖computePrefHeight()
prefWidth 和 min & max height & width 的方法以及其他计算方法。使用这种方法的详细描述很复杂,超出了本答案的范围。