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