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

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

问题描述

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

 儿童的总体高度(总和)
VBoxA 5 890
VBoxB 4 610
VBoxC 2 720

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

  private int getFreerColumnIndex(){
if(columns.isEmpty())
返回-1;

int columnIndex = 0;
int minHeight = 0;
for(int i = 0; i< columns.size(); i ++){
int height = 0;
for(节点n:columns.get(i).getChildren()){
height + = n.getBoundsInLocal()。getHeight();
}

if(i == 0){
minHeight = height;
}否则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



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






< h2>额外:

SomeNode 扩展节点



myPane上的方法addElement():

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

文档



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


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



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



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

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

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

  public void start(阶段阶段)抛出异常{
Group root = new Group();
场景场景=新场景(根);

按钮按钮=新按钮(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(场景);
stage.show();
}


替代



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


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

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;
}

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);
}

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(); 

will return 0 with the new nodes.

Anyone knows how to get the heigth of a node ?


Extra:

SomeNode extends of Node

Method addElement() at myPane:

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


Extra 2:

suppose we have 3 vbox: Before:

 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

解决方案

What you need to do is:

  1. Create the nodes which are to be placed in the VBoxes.
  2. 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).
  3. Call applyCss() and layout() on each of the nodes (or the dummy scene root).
  4. Measure the layout bounds of each of the nodes.
  5. Add the nodes to the VBoxes in your real scene according to your layout algorithm.

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.

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:

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() 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();
}

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.

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

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