当前位置: 首页 > 知识库问答 >
问题:

JavaFX setHgrow/binding属性无限扩展

高鸿振
2023-03-14

这是我的代码:

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的大小,并在调整窗口大小时改变它们的大小。我基本上想让它们模仿那个窗格的大小。

现在试着解释一下发生了什么,基本上我有一个基本上是正方形的类(稍后会有更多的东西),我想用它来填充我的“网格”。当我第一次这样做的时候,我使用了一个GridPane来扩展我的类,我还使用了注释掉的代码来绑定属性,它工作得“完美”,它调整了我想要的大小,没有任何问题,除了它像疯狂一样滞后,因为items ArrayList包含数千个项,所以这将是一个非常长的列表。后来,当我实现存储图像的盒子时,就出现了巨大的滞后问题。我的html" target="_blank">解决方案是用HBox和VBox组合来替换GridPane,这在很大程度上解决了延迟问题,它还允许我做GridPane做不到的事情。然而,我链接的gif中的问题是我所面临的。我尝试了我能想到的所有绑定属性组合,但它仍然疯狂地扩展,我只是不知道是什么导致了它,所以我真的希望这里的人能帮助我。我不知道JavaFX,但我来这里学习,非常感谢您的帮助。

共有1个答案

隗昀
2023-03-14

我认为您的问题的根本原因在于:与CustomBoxwidth绑定的squarewidth。你可能想知道这是个什么问题。您允许CustomBox的宽度取决于其内容(也称为正方形),而您的正方形宽度取决于其父宽度。。现在这两种宽度是相互依存的。。宽度呈指数增长。。

解决此问题的一种可能方法是,根据滚动窗格视口宽度手动计算CustomBox大小。通过这种方式,您可以手动控制父级宽度,内容宽度由绑定处理。

测试面板中的代码将是:

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 {
    }
}
 类似资料:
  • 有时候你需要给组件设置多个属性,你不想一个个写下这些属性,或者有时候你甚至不知道这些属性的名称,这时候 spread attributes 的功能就很有用了。 比如: var props = {}; props.foo = x; props.bar = y; var component = <Component {...props} />; props 对象的属性会被设置成 Component

  • 我正在使用SCEP为我的WebService创建证书。在成功创建证书和启动服务器之后,我尝试通过浏览器访问wsdl,浏览器显示一条错误消息,该消息表示该应用程序不允许使用证书类型,错误代码:SEC_ERROR_INSAPPLAYATE_CER_TYPE。一位同事指出,我必须将扩展密钥属性中的密钥用法更改为“服务器身份验证”,并且应该在认证请求中这样做。 要创建一个新请求,我使用BouncyCast

  • 在 Gradle 领域模型中所有被增强的对象能够拥有自己定义的属性. 这包括,但不仅限于 projects , tasks , 还有 source sets . Project 对象可以添加,读取,更改扩展的属性. 另外,使用 ext 扩展块可以一次添加多个属性. 例子 13.3. 使用扩展属性 build.gradle apply plugin: "java" ext { springV

  • 我有一个项目,它将成为现有ERP应用程序的附加组件。我已经让SSO正常工作,具有基本的Spring Security设置(请参阅我的票证:Grails和CAS基本设置)。此外,我没有使用s2快速入门。 我对Java开发还是新手,所以请耐心等待。。。我一直在浏览文档和示例,在某些方面,我对所看到的内容感到更困惑。我有几个问题: 1)此设置允许我访问登录用户的用户名,但仅此而已?如何访问User对象以

  • 我在我的组件中接收道具。我想在此组件中添加一个带有道具的属性“LegendPosition”。我不能那样做。请帮我做这个。我已经尝试过此代码,但没有成功:

  • SoapUI 提供了一种通用语法,用于在 SOAP 请求中动态插入属性。在他们的文档中,他们解释了如何根据属性范围访问不同的属性: 我的问题是我想访问当前testStep的名称,但是文档中说要访问testStep属性,你需要这个名称…还有其他方法吗?例如#TestCase#TestStep#Name。我知道如何使用groovy脚本实现这一点,但在我的例子中,我想将属性直接放在SOAP请求上。 先谢