2

当我在我的 Main (JavaFX) 类的 start 方法中运行以下代码时,我得到了奇怪的结果。窗口被显示,但pane(带有绿色边框)的宽度为 0。它应该与容器的高度具有相同的宽度,因为我将 prefWidth 绑定到了 height 属性。然后,当我调整窗口大小时,绑定生效,窗格变为正方形。请注意,如果我最大化窗口,它也不会应用绑定。

谢谢!

//Create a pane with a min width of 10 and a green border to be able to see it
Pane pane = new Pane();
pane.setStyle("-fx-border-color: green; -fx-border-width: 2");

//Bind the pane's preferred width to the pane's height
pane.prefWidthProperty().bind(pane.heightProperty());

//Put the pane in a vbox that does not fill the stage's width and make the pane grow in the vbox
VBox container = new VBox(pane);
container.setFillWidth(false);
VBox.setVgrow(pane, Priority.SOMETIMES);

//Show the vbox
primaryStage.setScene(new Scene(container, 600, 400));
primaryStage.show();
4

1 回答 1

3

您在这里遇到的问题是,当容器被布置时,它没有关于它应该计算宽度和高度的顺序的合理信息pane。所以本质上发生的是它计算宽度,它(因为它是空的)为零;然后计算高度(填充容器,因为您告诉了VBox这样做)。那之后,prefWidth属性被改变了,但是到那时实际的宽度已经设置好了,所以基本上已经太晚了。下次布局传递时,会考虑新的首选项宽度。

我没有检查实际的布局代码,但是(因为默认内容偏差为 null)很可能 vbox 的布局代码将执行与以下伪代码等效的操作:

protected void layoutChildren() {

    // content bias is null:
    double prefWidth = pane.prefWidth(-1);
    double prefHeight = pane.prefHeight(-1);

    // no fill width:
    double paneWidth = Math.max(this.getWidth(), prefWidth);
    // vgrow, so ignore preferred height and size to height of the vbox:
    double paneHeight = this.getHeight();
    pane.resizeRelocate(0, 0, paneWidth, paneHeight);

}

最后一次调用实际上会导致窗格的高度发生变化,然后prefWidth通过绑定导致窗格的高度发生变化。当然,这对于当前的布局通道来说已经太晚了,它已经根据之前的首选宽度计算设置了宽度。

基本上,像这样依赖绑定来管理布局并不是一种可靠的做事方式,因为您prefWidth布局过程中更改了属性(例如在此示例中) ,而此时调整组件的大小可能已经太迟了。

像这样管理窗格布局的可靠方法是覆盖适当的布局方法,这些方法由布局传递调用以调整组件的大小。

对于此示例,由于宽度取决于高度,因此您应该返回VERTICALcontentBias并且应该覆盖computePrefWidth(double height)以返回高度(因此宽度设置为高度):

@Override
public void start(Stage primaryStage) {
    Pane pane = new Pane() {
        @Override
        public Orientation getContentBias() {
            return Orientation.VERTICAL ;
        }
        @Override
        public double computePrefWidth(double height) {
            return height ;
        }
    };
    pane.setStyle("-fx-border-color: green; -fx-border-width: 2");


    //Bind the pane's preferred width to the pane's height
    //    pane.prefWidthProperty().bind(pane.heightProperty());

    //Put the pane in a vbox that does not fill the stage's width and make the pane grow in the vbox
    VBox container = new VBox(pane);
    container.setFillWidth(false);
    VBox.setVgrow(pane, Priority.SOMETIMES);

    //Show the vbox
    primaryStage.setScene(new Scene(container, 600, 400));
    primaryStage.show();
}
于 2018-05-23T01:16:18.357 回答