【问题标题】:JavaFX: How to center a TilePane but place the TilePane children from left-to-right?JavaFX:如何将 TilePane 居中,但将 TilePane 子项从左到右放置?
【发布时间】:2018-07-11 07:00:29
【问题描述】:

就像标题所暗示的那样,我试图在其父容器中居中 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 保持居中,而Region 子节点继续从左侧放置在每一行?

更新

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

【问题讨论】:

  • hmm .. 这正是指定的行为。不知道我明白你想要什么:在调整大小时,它应该保持居中直到下一个瓷砖适合,然后重新排列瓷砖,使第一行右侧的绿色永远不会显示?如果,我猜你需要实现一个自定义的 TilePane..
  • @kleopatra 是的,这就是我需要的。我不应该在第一排看到绿色空间。我希望有一个不需要我编写自定义控件的解决方法。
  • 挑剔:不是自定义控件,而是自定义窗格,基本上是自定义布局;)想知道为什么使用 VBox 作为父级?
  • @kleopatra 好吧,我尝试了一些不同的Pane 实现。他们通常给出相同的结果。我只需要一个可以将其子元素居中的窗格。
  • 在你的鞋子里,我会研究 TilePane 的实现 - 调整 computePrefXX 和 layoutChildren 可能就足够了(虽然从来没有做过布局,只适用于皮肤)

标签: java javafx javafx-8


【解决方案1】:

通过TilePane 设置图块的首选大小。通过将fillWidth 设置为false 并使用VBoxwidth 属性的侦听器设置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 child 上尝试过。

【讨论】:

  • 绑定向导 :) “跳跃”感觉有点令人沮丧——从用户体验的角度来看,我更喜欢左右边距的居中布局
  • 我对其进行了测试并且它有效,但我的大脑并没有设法捕捉到它是如何工作的。我需要一些时间来消化这个魔法xD
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多