获取JavaFX中节点的高度(生成布局pass) [英] Get the height of a node in JavaFX (generate a layout pass)

查看:37
本文介绍了获取JavaFX中节点的高度(生成布局pass)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 JavaFX 中获取节点的高度或偏好高度,我有 3 个 VBox 并且我想将节点添加到最自由的面板,例如:

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:

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

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

in this case, the most freer is the VBoxB, I calculate the most freer pane with this method:

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 个元素时才有效.但是如果我当时添加更多元素:

This method only works if I add 1 element at the time. But if I add more elements at the time:

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

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

the method getFreerColumnIndex return the same index. This is because the new nodes dont have heigth in local yet.
So this line:

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

将返回带有新节点的 0.

will return 0 with the new nodes.

有谁知道如何获得节点的高度?

Anyone knows how to get the heigth of a node ?

SomeNode 扩展 Node

myPane 中的方法 addElement():

Method addElement() at myPane:

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

<小时>

额外 2:

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


Extra 2:

suppose we have 3 vbox: Before:

 A      B      C
 |      |      |
        |      |
        |

运行:

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

之后:

 A      B      C
 |      |      |
 |      |      |
 |      |
 |
 |
 |
 |
 |
 |
 |
 |

正确:

 A      B      C
 |      |      |
 |      |      |
 |      |      |
 |      |      |
 |      |      |
 |

| = 某个节点

推荐答案

你需要做的是:

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

相关

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

To find out how to measure the size of a node, see the answer to:

背景

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

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.

文档

不幸的是node.applyCSS() 方法当前已损坏,因此我将在此处重现 Javadoc 代码中的示例,以便您可以在上下文中查看推荐的用法.对于下一个 Java 功能版本 (8u40),损坏的 javadoc 已修复为 RT-38330 的一部分Node 类的几个方法缺少 Javadoc,因此在该版本中,您将能够在 JavaFX javadoc 中找到以下文本:

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:

如果需要,将样式应用到此节点及其子节点(如果有).这种方法一般不需要可以直接调用,但可以与 layout() 结合使用以在下一个脉冲,或者如果场景不在舞台中.

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.

只要 Node 的 Scene 不为 null,CSS 就会应用到这个 Node 上,不管此节点的 CSS 状态是否干净.CSS 样式从最顶层的父级应用其 CSS 状态不是 clean 的 Node,这可能会影响其他节点的样式.如果节点不在场景中,则此方法无操作.场景不必在舞台上.

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.

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

This method does not invoke the layout() method. Typically, the caller will use the following sequence of operations.

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

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

As a more complete example, the following code uses applyCss() and layout() to find the width and height of the Button before the Stage has been shown. If either the call to applyCss() or the call to layout() is commented out, the calls to getWidth() and getHeight() 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();
}

替代

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

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.

这篇关于获取JavaFX中节点的高度(生成布局pass)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆