在 GridPane 内容上指定 JavaFX CSS 边框是否应该折叠大小?

Is specifying JavaFX CSS borders on GridPane contents supposed to collapse the sizing?

当我 运行 遇到以下问题时,我试图使用 GridPane 布局 JavaFX 阶段。如果我使用适当的约束设置网格并向其添加新实例化的 StackPane,则场景、舞台及其内容的默认大小可确保内容可见:

但是,如果我在将新实例化的 StackPane 添加到 GridPane 之前将指定边框的 JavaFX CSS 样式添加到 GridPane,那么事物的默认大小似乎会崩溃完成:

我的代码如下:

public static void main(final String[] args) {
    Platform.startup(() -> {});
    Platform.runLater(() -> {

        final GridPane gridPane = new GridPane();
        final Scene scene = new Scene(gridPane);
        final Stage stage = new Stage();
        stage.setScene(scene);

        final List<StackPane> panes = new ArrayList<>();
        for (int i = 0; i < 4; i++) {

            // Create a new pane with a random background color for
            // illustration
            final StackPane p = createNewPane();
            panes.add(p);

            // The addition / removal of the following line affects the
            // layout.
            p.setStyle("-fx-border-width:2px;-fx-border-color:red");
        }

        for (int r = 0; r < 2; r++) {
            final RowConstraints rc = new RowConstraints();
            rc.setPercentHeight(50);
            gridPane.getRowConstraints().add(rc);
        }
        for (int c = 0; c < 2; c++) {
            final ColumnConstraints cc = new ColumnConstraints();
            cc.setPercentWidth(50);
            gridPane.getColumnConstraints().add(cc);
        }

        for (int r = 0, i = 0; r < 2; r++) {
            for (int c = 0; c < 2; c++) {
                gridPane.add(panes.get(i++), c, r);
            }
        }
        stage.show();
    });
}

奇怪的是,如果我在设置场景后将 stage.show() 移到右侧,那么即使使用 CSS 也一切正常。

任何人都可以帮助我理解,第一,这是否是预期的行为,第二,为什么 stage.show() 的执行顺序会有所不同?

谢谢!

问题是什么

你的例子有点含糊。您不会随时设置添加到舞台的任何内容的首选大小。因此,JavaFX 平台真的可以在调整大小方面做任何它想做的事情。设置首选百分比大小与设置首选绝对大小不同。百分比大小是相对的,所以问题就变成了,相对于什么?答案尚不清楚。

至于为什么会这样:

// The addition / removal of the following line affects the
// layout.
p.setStyle("-fx-border-width:2px;-fx-border-color:red");

我说不准。我的猜测是 CSS 的使用会触发一些额外的布局逻辑,这些逻辑会在没有任何大小提示的情况下影响调整大小。

如何修复

无论如何,解决方案只是让事情变得更清楚,并至少为应用程序中的某些内容指定首选大小,然后应用程序最初将调整为该首选大小。

这是一个例子:

import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Starter {
    public static void main(String[] args) {
        Platform.startup(() -> {});
        Platform.runLater(() -> {
            final GridPane gridPane = new GridPane();
            final Scene scene = new Scene(gridPane);
            final Stage stage = new Stage();
            stage.setScene(scene);

            final List<StackPane> panes = new ArrayList<>();
            for (int i = 0; i < 4; i++) {

                // Create a new pane with a random background color for
                // illustration
                final StackPane p = createNewPane();
                panes.add(p);

                // The addition / removal of the following line affects the
                // layout.
                p.setStyle("-fx-border-width:2px;-fx-border-color:red");
            }

            for (int r = 0; r < 2; r++) {
                final RowConstraints rc = new RowConstraints();
                rc.setPercentHeight(50);
                gridPane.getRowConstraints().add(rc);
            }
            for (int c = 0; c < 2; c++) {
                final ColumnConstraints cc = new ColumnConstraints();
                cc.setPercentWidth(50);
                gridPane.getColumnConstraints().add(cc);
            }

            for (int r = 0, i = 0; r < 2; r++) {
                for (int c = 0; c < 2; c++) {
                    gridPane.add(panes.get(i++), c, r);
                }
            }
            stage.show();
        });
    }

    private static final Random random = new Random(42);

    private static StackPane createNewPane() {
        StackPane pane = new StackPane();

        pane.setBackground(
                new Background(
                        new BackgroundFill(
                                randomColor(), null, null
                        )
                )
        );

        pane.setPrefSize(150, 100);

        return pane;
    }

    private static Color randomColor() {
        return Color.rgb(
                random.nextInt(256),
                random.nextInt(256),
                random.nextInt(256)
        );
    }
}

解决方案的关键部分是调用:

pane.setPrefSize(150, 100);

设置放置在布局中的堆栈窗格的首选大小。

或者,不是通过在每个 StackPanes 上设置首选大小来进行自下而上的首选大小调整,您也可以通过在 GridPane 上设置适当的约束来从自上而下的角度完成类似的事情,例如:

 gridPane.setPrefSize(300, 200);

备注

我建议使用 JavaFX Application class instead of Platform.startup() 调用,除非确实有充分的理由使用后者(在本例中是这样的——与 Swing 接口,正如您在评论中指出的那样)。