如果在布局之后调用过快,则JavaFX Node.getBoundsInParent()将失败

如果在布局之后调用过快,则JavaFX Node.getBoundsInParent()将失败,javafx,jython,race-condition,Javafx,Jython,Race Condition,如果在将节点添加到GridPane后过早调用Node.getBoundsInParent(),则返回的Bounds对象的成员都是0.0。看,一些Java代码演示了我的问题: import java.lang.Runnable; import java.util.ArrayList; import java.util.List; import javafx.application.Application; import javafx.application.Platform; import jav

如果在将节点添加到
GridPane
后过早调用
Node.getBoundsInParent()
,则返回的
Bounds
对象的成员都是
0.0
。看,一些Java代码演示了我的问题:

import java.lang.Runnable;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;

public class MyApplication extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        List<Label> labels = new ArrayList<Label>();
        for (int index = 0; index < 12; ++index) {
            labels.add(new Label(String.format("%d", index)));
        }

        GridPane gridPane = new GridPane();

        Button layoutButton = new Button("Layout");
        layoutButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    gridPane.getChildren().setAll(labels);
                    for (int index = 0; index < labels.size(); ++index) {
                        gridPane.setConstraints(labels.get(index), 0, index);
                    }
                }
            });

        Button getBoundsButton = new Button("Get Bounds");
        getBoundsButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println(labels.get(0).getBoundsInParent());
                }
            });

        Button layoutAndGetBoundsButton = new Button("Layout and Get Bounds");
        layoutAndGetBoundsButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    gridPane.getChildren().setAll(labels);
                    for (int index = 0; index < labels.size(); ++index) {
                        gridPane.setConstraints(labels.get(index), 0, index);
                    }

                    System.out.println(labels.get(0).getBoundsInParent());
                }
            });

        Button layoutAndGetBoundsLaterButton = new Button("Layout and Get Bounds Later");
        layoutAndGetBoundsLaterButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    gridPane.getChildren().setAll(labels);
                    for (int index = 0; index < labels.size(); ++index) {
                        gridPane.setConstraints(labels.get(index), 0, index);
                    }

                    class MyRunnable implements Runnable {
                        Label label;
                        public MyRunnable(Label label) {
                            this.label = label;
                        }
                        @Override
                        public void run() {
                            System.out.println(this.label.getBoundsInParent());
                        }
                    }

                    Platform.runLater(new MyRunnable(labels.get(0)));
                }
            });

        VBox vbox = new VBox();
        vbox.getChildren().setAll(
            layoutButton,
            getBoundsButton,
            layoutAndGetBoundsButton,
            layoutAndGetBoundsLaterButton);

        HBox hbox = new HBox();
        hbox.getChildren().setAll(vbox, gridPane);

        primaryStage.setTitle("Race Condition?");
        primaryStage.setScene(new Scene(hbox, 320, 240));
        primaryStage.show();
    }

}
  • 如果我按顺序单击“布局”和“获取边界”按钮,我的程序将按预期打印包含一些非零成员的边界框

  • 如果单击“布局并获取边界”按钮,我的程序将打印一个所有成员都设置为零的边界框。(再次单击此按钮将打印预期结果。)

  • 如果我单击“布局并稍后获取边界”按钮,结果也不会更好

另外,我现在看到了
GridPane
的这个问题,但我也看到了其他JavaFX控件的类似问题:我让它做一件事,然后让它做另一件事,但它还没有准备好做第二件事

我做错了什么


更新:我似乎与作为“非问题”而关闭的解决方案有冲突。

我有一个解决方案,但它很难看,而且不太可靠

我的解决方法是将对
节点.getBoundsInParent()的调用置于事件处理程序内部,然后使用动画将其延迟毫秒:

def printBounds(event):
    print labels[0].getBoundsInParent()

import javafx.animation.Timeline as Timeline
import javafx.animation.KeyFrame as KeyFrame
import javafx.util.Duration as Duration

timeline = Timeline([
        KeyFrame(
            Duration.millis(1), printBounds, [])])
timeline.play()
这足以使
网格窗格
稳定下来,以便
节点
将返回正确的边界

请告诉我有更好的办法

def printBounds(event):
    print labels[0].getBoundsInParent()

import javafx.animation.Timeline as Timeline
import javafx.animation.KeyFrame as KeyFrame
import javafx.util.Duration as Duration

timeline = Timeline([
        KeyFrame(
            Duration.millis(1), printBounds, [])])
timeline.play()