JavaFX:如何居中放置TilePane,但从左到右放置TilePane子对象?

JavaFX:如何居中放置TilePane,但从左到右放置TilePane子对象?,java,javafx,javafx-8,Java,Javafx,Javafx 8,正如标题所示,我试图将TilePane置于其父容器的中心,但同时,我希望TilePane的子节点从左到右放置 @Override public void start(final Stage primaryStage) throws Exception { final VBox root = new VBox(); final Scene sc = new Scene(root); primaryStage.setScene(sc); final Tile

正如标题所示,我试图将
TilePane
置于其父容器的中心,但同时,我希望
TilePane
的子节点从左到右放置

@Override
public void start(final Stage primaryStage) throws Exception {
    final VBox root = new VBox();
    final Scene sc = new Scene(root);
    primaryStage.setScene(sc);
    
    final TilePane tp = new TilePane();
    root.getChildren().add(tp);
    
    tp.setPrefColumns(3);
    tp.setAlignment(Pos.TOP_LEFT);
    tp.setStyle("-fx-background-color: green;");
    root.setAlignment(Pos.CENTER);
    root.setFillWidth(true);

    Stream.iterate(0, i -> i + 1).limit(5).forEach(i -> {
        Region r = new Region();
        r.setPrefSize(200, 200);
        r.setStyle("-fx-background-color: red; -fx-border-color: blue; -fx-border-width: 1;");

        tp.getChildren().add(r);
    });

    primaryStage.show();
}
这将创建如下窗口:

增加窗口宽度会导致以下情况:

继续增加窗高会导致以下情况:

设置
root.setFillWidth(false)
会导致:

如何确保整个
TilePane
保持居中,而
区域
子节点继续从左侧放置在每行上

更新
为了更清楚,在调整大小期间,
TilePane
应尝试在除顶行以外的所有行中放入尽可能多的平铺(本例中的区域)。换言之,第一排的右侧不应有任何绿地。或者,左侧和右侧的绿地应相等。此外,瓷砖必须从左到右放置。设置
TilePane.setAlignment(Pos.CENTER)
会将任何“剩余”瓷砖放置在最后一行的中心,这是不可接受的。

通过
TilePane设置瓷砖的首选尺寸。通过将
fillWidth
设置为
false
并使用
VBox
width
属性的侦听器设置
prefColumns
属性,防止父级将
TilePane
的大小调整到其首选大小之外:

@Override
public void start(Stage primaryStage) {
    final VBox root = new VBox();
    final Scene sc = new Scene(root);
    primaryStage.setScene(sc);

    final TilePane tp = new TilePane();
    tp.setPrefTileWidth(200);
    tp.setPrefTileHeight(200);
    root.getChildren().add(tp);

    tp.setPrefColumns(3);
    tp.setAlignment(Pos.TOP_LEFT);
    tp.setStyle("-fx-background-color: green;");
    root.setAlignment(Pos.CENTER);
    root.setFillWidth(false);

    // set prefColumns from a listener instead of a binding
    // to prevent the initial value from being set to 0
    root.widthProperty().addListener((o, oldValue, newValue) -> {
        // allow as many columns as fit the parent but keep it in
        // range [1, childCount]
        tp.setPrefColumns(Math.min(tp.getChildren().size(),
                Math.max(1, (int) (newValue.doubleValue() / tp.getPrefTileWidth()))));
    });

    Stream.iterate(0, i -> i + 1).limit(5).forEach(i -> {
        Region r = new Region();
        r.setStyle("-fx-background-color: red; -fx-border-color: blue; -fx-border-width: 1;");

        tp.getChildren().add(r);
    });

    primaryStage.show();
}
由OP更新 我对这种方法感到惊讶,我尝试了一些更具活力的方法

root.widthProperty().addListener((o, oldValue, newValue) -> {
    double maxWidth = tp.getChildren()
                        .stream()
                        .filter(n -> n instanceof Region)
                        .map(n -> ((Region) n).getWidth())
                        .max(Double::compareTo)
                        .orElse(0d);

    tp.setPrefColumns(Math.min(tp.getChildren().size(),
            Math.max(1, (int) (newValue.doubleValue() / maxWidth))));
});

Stream.iterate(0, i -> i + 1).limit(5).forEach(i -> {
    Region r = new Region();
    Random random = new Random();
    r.setPrefSize(random.nextInt(150) + 50, random.nextInt(150) + 50);
    System.out.println(r.getPrefWidth());
    System.out.println(r.getPrefHeight());
    r.setStyle("-fx-background-color: red; -fx-border-color: blue; -fx-border-width: 1;");

    tp.getChildren().add(r);
});
这样就不需要为每个平铺设置静态宽度/高度


虽然这在这个基本示例中有效,但我已经在更复杂的tile儿童身上尝试过了。

hmm。。这正是规定的行为。我不知道你想要什么:在调整大小时,它应该保持居中,直到下一个平铺合适,然后重新排列平铺,这样第一行右侧的绿色永远不会显示?如果,我猜你需要实现一个定制的TilePane。@kleopatra是的,这就是我需要的。我不应该看到第一排的绿地。我希望有一个解决方案,不需要我编写自定义控件。挑剔:不是自定义控件,而是自定义窗格,基本上就是自定义布局;)想知道为什么要使用VBox作为父对象?@kleopatra嗯,我尝试了几种不同的
窗格
实现。它们通常给出相同的结果。我只需要一个可以将其子对象居中的窗格。以您的角度来看,我会研究TilePane的实现-调整computePrefXX和layoutChildren可能就足够了(尽管从未对布局进行过调整,只对皮肤进行过调整)绑定向导:)这种“跳跃”感觉有点令人沮丧,尽管如此,从用户体验的角度来看,我更喜欢左边和右边有边距的居中布局。我测试了它,它工作了,但我的大脑还没有捕捉到它是如何工作的。我需要一些时间来消化这个神奇的xD