Проблема, с которой вы здесь сталкиваетесь, заключается в том, что при разметке контейнера у него нет разумной информации о порядке, в котором он должен вычислять ширину и высоту pane
.По сути, происходит то, что он вычисляет ширину, которая (поскольку она пустая) равна нулю;затем вычисляет высоту (которая заполняет контейнер, так как вы сказали VBox
сделать это). После это свойство prefWidth
изменяется, но к тому времени фактическая ширина уже была установлена, так что по сути уже слишком поздно.При следующем прохождении макета учитывается новая ширина префа.
Я не проверял фактический код макета, но (поскольку смещение содержимого по умолчанию равно нулю), скорее всего, код макета для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();
}