JavaFX:如何将 TilePane 居中但将 TilePane children 从 left-to-right 放置?
JavaFX: How to center a TilePane but place the TilePane children from left-to-right?
如标题所示,我试图将 TilePane
置于其 parent 容器的中心,但与此同时,我想要 child 节点 TilePane
从 left-to-right.
放置
@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();
}
这会创建一个像这样的 window:
增加 window 宽度会导致:
继续增加 window 高度会导致:
设置 root.setFillWidth(false)
导致:
我该怎么做才能确保整个 TilePane
保持居中,同时 Region
child 节点继续从左侧放置在每一行上?
更新
为了更清楚,TilePane
应该在调整大小时尝试在除顶行之外的所有行中适应尽可能多的图块(本例中的区域)。也就是说,第一行右边不应该有任何绿色的space。或者,绿色 space 应该在左侧和右侧相等。此外,瓷砖必须从左到右放置。设置 TilePane.setAlignment(Pos.CENTER)
会将任何“剩余”图块放在最后一行的中心,这是不可接受的。
通过 TilePane
设置磁贴的首选大小。通过将 fillWidth
设置为 false
并使用监听器 width
属性 的 VBox
设置 prefColumns
属性:
@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);
});
这样就无需为每个图块设置静态 width/height。
虽然这在这个基本示例中有效,但我已经在更复杂的图块子项上尝试过。
如标题所示,我试图将 TilePane
置于其 parent 容器的中心,但与此同时,我想要 child 节点 TilePane
从 left-to-right.
@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();
}
这会创建一个像这样的 window:
增加 window 宽度会导致:
继续增加 window 高度会导致:
设置 root.setFillWidth(false)
导致:
我该怎么做才能确保整个 TilePane
保持居中,同时 Region
child 节点继续从左侧放置在每一行上?
更新
为了更清楚,TilePane
应该在调整大小时尝试在除顶行之外的所有行中适应尽可能多的图块(本例中的区域)。也就是说,第一行右边不应该有任何绿色的space。或者,绿色 space 应该在左侧和右侧相等。此外,瓷砖必须从左到右放置。设置 TilePane.setAlignment(Pos.CENTER)
会将任何“剩余”图块放在最后一行的中心,这是不可接受的。
通过 TilePane
设置磁贴的首选大小。通过将 fillWidth
设置为 false
并使用监听器 width
属性 的 VBox
设置 prefColumns
属性:
@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);
});
这样就无需为每个图块设置静态 width/height。
虽然这在这个基本示例中有效,但我已经在更复杂的图块子项上尝试过。