JavaFX setHgrow / binding 属性 无限扩展
JavaFX setHgrow / binding property expanding infinitely
这是我的代码:
public class TestPanel extends ScrollPane {
final int SPACING = 5;
final int ROW_MAX = 6;
public TestPanel(ArrayList<Item> items) {
VBox root = new VBox();
root.setSpacing(SPACING);
HBox row = null;
int count = 0;
for (Item item: items){
if (count == ROW_MAX || row == null){
row = new HBox();
row.setSpacing(SPACING);
root.getChildren().add(row);
count = 0;
}
CustomBox box = new customBox(item);
row.getChildren().add(box);
HBox.setHgrow(box, Priority.ALWAYS);
//box.prefWidthProperty().bind(row.widthProperty()); // Worked for GridPane
count++;
}
setFitToWidth(true);
setContent(root);
}
这是我放置在 V 和 H 框中的自定义框节点元素
public class CustomBox extends StackPane {
private Items item;
private Rectangle square;
private int size = 20; // Irrelevent
public CustomBox(NewAirbnbListing item) {
this.item= item;
setPadding(new Insets(5, 5, 5, 5));
square = new Rectangle(size, size, Color.RED);
square.widthProperty().bind(widthProperty());
//square.heightProperty().bind(heightProperty());
minHeightProperty().bind(widthProperty()); // Maintains aspect ratio
getChildren().add(square);
}
错误:粉色是盒子,灰色是 StackPane 的背景色,用于视觉测试。
我想做的事情:
我想要的:我希望 CustomBox 内的矩形(以及我稍后将添加的其他组件)填充它们所在的 StackPane 的大小,并在 window 调整大小。我基本上希望他们模仿那个窗格的大小。
现在试着解释一下发生了什么,基本上我有一个 class 基本上是一个正方形(稍后会有更多的东西),我想用它来填充我的“网格”。当我第一次这样做时,我使用 GridPane 来扩展我的 class,我还使用注释掉的代码来绑定属性并且它“完美地”工作,它调整了我想要的大小没有任何问题,除了它滞后的事实太疯狂了,因为项目 ArrayList 包含数千个项目,所以这将是一个很长的列表。后来,当我实现存储图像的盒子时,大量的滞后问题就开始了。我的解决方案是用 HBox 和 VBox 组合替换 GridPane,它很好地解决了延迟问题,它还让我可以做一些我不能用 GridPane 做的事情。但是,我链接的 gif 中的问题是我面临的问题。我已经尝试了我能想到的所有绑定属性组合,但它仍然像疯了一样扩展,我只是不知道是什么原因造成的,所以我真的希望这里有人能帮助我。我不太了解 JavaFX,但我是来学习的,非常感谢任何帮助。
我认为您的问题的根本原因在于:square
宽度与 CustomBox
宽度绑定。你可能想知道这是怎么回事。您允许 CustomBox 宽度依赖于它的内容(a.k.a 正方形)并且您的正方形宽度依赖于它的父宽度。因为现在这两个宽度是相互依赖的。宽度呈指数增加。 .
解决此问题的一种可能方法是根据 ScrollPane 视口宽度手动计算 CustomBox 大小。这样你就可以手动控制父级宽度,内容宽度由绑定处理。
TestPanel 中的代码将是:
private DoubleProperty size = new SimpleDoubleProperty();
double padding = 4; // 2px on either side
viewportBoundsProperty().addListener((obs, old, bounds) -> {
size.setValue((bounds.getWidth() - padding - ((ROW_MAX - 1) * SPACING)) / ROW_MAX);
});
CustomBox box = new CustomBox(item);
box.minWidthProperty().bind(size);
完整的工作演示如下:
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class ScrollPaneContentDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
List<Item> items = new ArrayList<>();
IntStream.range(1, 1000).forEach(i -> items.add(new Item()));
TestPanel root = new TestPanel(items);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.setTitle("ScrollPaneContent Demo");
stage.show();
}
class TestPanel extends ScrollPane {
private final int SPACING = 5;
private final int ROW_MAX = 6;
private DoubleProperty size = new SimpleDoubleProperty();
public TestPanel(List<Item> items) {
final VBox root = new VBox();
root.setSpacing(SPACING);
HBox row = null;
int count = 0;
for (Item item : items) {
if (count == ROW_MAX || row == null) {
row = new HBox();
row.setSpacing(SPACING);
root.getChildren().add(row);
count = 0;
}
CustomBox box = new CustomBox(item);
box.minWidthProperty().bind(size);
row.getChildren().add(box);
HBox.setHgrow(box, Priority.ALWAYS);
count++;
}
setFitToWidth(true);
setContent(root);
double padding = 4;
viewportBoundsProperty().addListener((obs, old, bounds) -> {
size.setValue((bounds.getWidth() - padding - ((ROW_MAX - 1) * SPACING)) / ROW_MAX);
});
}
}
class CustomBox extends StackPane {
private Item item;
private Rectangle square;
private int size = 20;
public CustomBox(Item item) {
setStyle("-fx-background-color:#99999950;");
this.item = item;
setPadding(new Insets(5, 5, 5, 5));
square = new Rectangle(size, size, Color.RED);
square.widthProperty().bind(widthProperty());
square.heightProperty().bind(heightProperty());
maxHeightProperty().bind(minWidthProperty());
maxWidthProperty().bind(minWidthProperty());
minHeightProperty().bind(minWidthProperty());
getChildren().add(square);
}
}
class Item {
}
}
这是我的代码:
public class TestPanel extends ScrollPane {
final int SPACING = 5;
final int ROW_MAX = 6;
public TestPanel(ArrayList<Item> items) {
VBox root = new VBox();
root.setSpacing(SPACING);
HBox row = null;
int count = 0;
for (Item item: items){
if (count == ROW_MAX || row == null){
row = new HBox();
row.setSpacing(SPACING);
root.getChildren().add(row);
count = 0;
}
CustomBox box = new customBox(item);
row.getChildren().add(box);
HBox.setHgrow(box, Priority.ALWAYS);
//box.prefWidthProperty().bind(row.widthProperty()); // Worked for GridPane
count++;
}
setFitToWidth(true);
setContent(root);
}
这是我放置在 V 和 H 框中的自定义框节点元素
public class CustomBox extends StackPane {
private Items item;
private Rectangle square;
private int size = 20; // Irrelevent
public CustomBox(NewAirbnbListing item) {
this.item= item;
setPadding(new Insets(5, 5, 5, 5));
square = new Rectangle(size, size, Color.RED);
square.widthProperty().bind(widthProperty());
//square.heightProperty().bind(heightProperty());
minHeightProperty().bind(widthProperty()); // Maintains aspect ratio
getChildren().add(square);
}
错误:粉色是盒子,灰色是 StackPane 的背景色,用于视觉测试。
我想做的事情:
我想要的:我希望 CustomBox 内的矩形(以及我稍后将添加的其他组件)填充它们所在的 StackPane 的大小,并在 window 调整大小。我基本上希望他们模仿那个窗格的大小。
现在试着解释一下发生了什么,基本上我有一个 class 基本上是一个正方形(稍后会有更多的东西),我想用它来填充我的“网格”。当我第一次这样做时,我使用 GridPane 来扩展我的 class,我还使用注释掉的代码来绑定属性并且它“完美地”工作,它调整了我想要的大小没有任何问题,除了它滞后的事实太疯狂了,因为项目 ArrayList 包含数千个项目,所以这将是一个很长的列表。后来,当我实现存储图像的盒子时,大量的滞后问题就开始了。我的解决方案是用 HBox 和 VBox 组合替换 GridPane,它很好地解决了延迟问题,它还让我可以做一些我不能用 GridPane 做的事情。但是,我链接的 gif 中的问题是我面临的问题。我已经尝试了我能想到的所有绑定属性组合,但它仍然像疯了一样扩展,我只是不知道是什么原因造成的,所以我真的希望这里有人能帮助我。我不太了解 JavaFX,但我是来学习的,非常感谢任何帮助。
我认为您的问题的根本原因在于:square
宽度与 CustomBox
宽度绑定。你可能想知道这是怎么回事。您允许 CustomBox 宽度依赖于它的内容(a.k.a 正方形)并且您的正方形宽度依赖于它的父宽度。因为现在这两个宽度是相互依赖的。宽度呈指数增加。 .
解决此问题的一种可能方法是根据 ScrollPane 视口宽度手动计算 CustomBox 大小。这样你就可以手动控制父级宽度,内容宽度由绑定处理。
TestPanel 中的代码将是:
private DoubleProperty size = new SimpleDoubleProperty();
double padding = 4; // 2px on either side
viewportBoundsProperty().addListener((obs, old, bounds) -> {
size.setValue((bounds.getWidth() - padding - ((ROW_MAX - 1) * SPACING)) / ROW_MAX);
});
CustomBox box = new CustomBox(item);
box.minWidthProperty().bind(size);
完整的工作演示如下:
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class ScrollPaneContentDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
List<Item> items = new ArrayList<>();
IntStream.range(1, 1000).forEach(i -> items.add(new Item()));
TestPanel root = new TestPanel(items);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.setTitle("ScrollPaneContent Demo");
stage.show();
}
class TestPanel extends ScrollPane {
private final int SPACING = 5;
private final int ROW_MAX = 6;
private DoubleProperty size = new SimpleDoubleProperty();
public TestPanel(List<Item> items) {
final VBox root = new VBox();
root.setSpacing(SPACING);
HBox row = null;
int count = 0;
for (Item item : items) {
if (count == ROW_MAX || row == null) {
row = new HBox();
row.setSpacing(SPACING);
root.getChildren().add(row);
count = 0;
}
CustomBox box = new CustomBox(item);
box.minWidthProperty().bind(size);
row.getChildren().add(box);
HBox.setHgrow(box, Priority.ALWAYS);
count++;
}
setFitToWidth(true);
setContent(root);
double padding = 4;
viewportBoundsProperty().addListener((obs, old, bounds) -> {
size.setValue((bounds.getWidth() - padding - ((ROW_MAX - 1) * SPACING)) / ROW_MAX);
});
}
}
class CustomBox extends StackPane {
private Item item;
private Rectangle square;
private int size = 20;
public CustomBox(Item item) {
setStyle("-fx-background-color:#99999950;");
this.item = item;
setPadding(new Insets(5, 5, 5, 5));
square = new Rectangle(size, size, Color.RED);
square.widthProperty().bind(widthProperty());
square.heightProperty().bind(heightProperty());
maxHeightProperty().bind(minWidthProperty());
maxWidthProperty().bind(minWidthProperty());
minHeightProperty().bind(minWidthProperty());
getChildren().add(square);
}
}
class Item {
}
}