Привязка JavaFX применяется только после изменения размера окна - PullRequest
0 голосов
/ 23 мая 2018

Когда я запускаю следующий код в методе запуска моего класса Main (JavaFX), я получаю странные результаты.Окно отображается, но ширина 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();

1 Ответ

0 голосов
/ 23 мая 2018

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