当我在我的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();
答案 0 :(得分:3)
您遇到的问题是,当容器布局时,它没有合理的信息来说明它应该计算pane
的宽度和高度的顺序。所以实际上发生的是它计算宽度,因为它是空的(因为它是空的)是零;然后计算高度(填充容器,因为你告诉VBox
这样做)。 在之后,prefWidth
属性被更改,但到那时已经设置了实际宽度,所以它本来就太晚了。下次进行布局传递时,会考虑新的pref宽度。
我还没有检查过实际的布局代码,但是(由于默认内容偏差为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
)在布局过程中,当调整组件的大小可能已经太晚了。
管理这样一个窗格的布局的可靠方法是覆盖相应的布局方法,布局方法调用这些布局方法以调整组件的大小。
对于此示例,由于宽度取决于高度,因此您应该为VERTICAL
返回contentBias
,并且应覆盖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();
}