JavaFX使用线程动态更快地填充GridPane

JavaFX使用线程动态更快地填充GridPane,java,multithreading,javafx,java-threads,Java,Multithreading,Javafx,Java Threads,我正在从数据库加载数据,并在GridPane中动态创建按钮!但是由于数据量很大,要看到按钮需要花费太长时间! 我正在使用线程从DB加载数据,但似乎创建每个按钮和填充GridPane花费的时间太长了 **我试着创建硬编码数据并用它们填充GridPane只是为了测试,但这需要很长时间,因此我得出结论,导致按钮显示时间过长的问题是填充GridPane,而不是从DB加载数据 有没有办法更快地填充网格窗格? 我使用2个循环,一个用于行,另一个用于列,因此复杂性是(n平方) 我可以优化它吗 以下是我创建和填

我正在从数据库加载数据,并在GridPane中动态创建按钮!但是由于数据量很大,要看到按钮需要花费太长时间! 我正在使用线程从DB加载数据,但似乎创建每个按钮和填充GridPane花费的时间太长了

**我试着创建硬编码数据并用它们填充GridPane只是为了测试,但这需要很长时间,因此我得出结论,导致按钮显示时间过长的问题是填充GridPane,而不是从DB加载数据

有没有办法更快地填充网格窗格? 我使用2个循环,一个用于行,另一个用于列,因此复杂性是(n平方)

我可以优化它吗

以下是我创建和填充GridPane的函数:

public void initialize() throws Exception {
    initializedProducts = new ArrayList<>();
    productsOnReceipt = new ArrayList<>();
    rows = new VBox();
    grandPrice = 0;

    //Initializing DatabaseConnections and accessors for each sections
    ProductDao burgerAccessor = new ProductDaoImpl();
    ProductDao burgerMenuAccessor = new ProductDaoImpl();
    ProductDao drinksAccessor = new ProductDaoImpl();

    Executor exec = Executors.newCachedThreadPool(runnable -> {
        Thread t = new Thread(runnable);
        t.setDaemon(true);
        return t;
    });

    initSections(burgers_section, 2, "PICI", exec, burgerAccessor);
    initSections(burgersMenu_section, 2, "TOPLI JADENJA", exec, burgerMenuAccessor);
    initSections(drinks_section, 1, "BEZALKOHOLNI PIJALOCI", exec, drinksAccessor);
}
初始化每个部分的产品:

private void initProducts(GridPane grid, int rows, String category, Executor executor, ProductDao accessor) {
    Task<Products> productsResultTask = new Task<Products>() {
        @Override
        protected Products call() throws Exception {
            return accessor.getByCategory(category);
        }
    };

    productsResultTask.setOnFailed(e -> productsResultTask.getException().printStackTrace());

    productsResultTask.setOnSucceeded(e -> {
        if (productsResultTask.getValue() != null) {
            ArrayList<Product> products = productsResultTask.getValue().getProducts();
            int productCounter = 0;
            if (rows == 1) {
                for (int j = 0; j < products.size(); j++) {
                    initializeButton(category, products.get(productCounter), grid, 0, j);
                    initializedProducts.add(products.get(productCounter));
                    productCounter++;
                }
            } else {
                if (isEven(products.size())) {
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < products.size() / 2; j++) {
                            initializeButton(category, products.get(productCounter), grid, i, j);
                            initializedProducts.add(products.get(productCounter));
                            productCounter++;
                        }
                    }
                } else {
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < (products.size()-1) / 2; j++) {
                            initializeButton(category, products.get(productCounter), grid, i, j);
                            initializedProducts.add(products.get(productCounter));
                            productCounter++;
                        }
                    }
                    initializeButton(category, products.get(productCounter), grid, 0, ((products.size() - 1) / 2));
                    initializedProducts.add(products.get(productCounter));
                }
            }
        } else {
            System.out.println("Can't fetch products from DB!");
        }
    });
    executor.execute(productsResultTask);
}

你有一些潜在的性能杀手在那里

你为什么一次又一次地加载背景图片。您可以在循环之外加载它一次并重用它

尽量将代码减少到绝对最小值。没有任何CSS和其他装饰的普通按钮,然后比较性能


你能提供一些数字吗。什么对你来说是慢的?

你有一些潜在的性能杀手

你为什么一次又一次地加载背景图片。您可以在循环之外加载它一次并重用它

尽量将代码减少到绝对最小值。没有任何CSS和其他装饰的普通按钮,然后比较性能


你能提供一些数字吗。什么对你来说比较慢?

“我用2个表示循环,一个表示行,另一个表示列,所以复杂度是(n平方)!”这样的说法是误导性的。您没有指定
n
是什么,但很可能是您错了:产品的数量似乎与
无关,导致复杂性
行*products.size()
。对于大量产品,最好使用虚拟化控件。可能是一种选择。此外,无需对循环执行2个独立的嵌套:整数除法结果四舍五入到0。是的,我想说的是复杂性
rows*products.size()
我的错误!我不知道如何虚拟化控制,我会尝试一下!对于两个独立的嵌套For循环,这不是因为除以奇数,而是因为如果产品的数量是奇数,我会做与偶数产品相同的事情(用产品填充两行),最后在最后一列的第一行再添加一个产品!也许我可以通过为嵌套for循环使用一个函数来重构它,这样我就不会重复相同的代码了!但是,我的主要问题是性能!“我用2个表示循环,一个表示行,另一个表示列,所以复杂度是(n平方)!”这样的说法是误导性的。您没有指定
n
是什么,但很可能是您错了:产品的数量似乎与
无关,导致复杂性
行*products.size()
。对于大量产品,最好使用虚拟化控件。可能是一种选择。此外,无需对循环执行2个独立的嵌套:整数除法结果四舍五入到0。是的,我想说的是复杂性
rows*products.size()
我的错误!我不知道如何虚拟化控制,我会尝试一下!对于两个独立的嵌套For循环,这不是因为除以奇数,而是因为如果产品的数量是奇数,我会做与偶数产品相同的事情(用产品填充两行),最后在最后一列的第一行再添加一个产品!也许我可以通过为嵌套for循环使用一个函数来重构它,这样我就不会重复相同的代码了!但是,我的主要问题是性能!这不是问题的答案。如果你需要让OP澄清一些事情,请将其作为评论而不是答案发布。关于背景图像:每个产品(按钮)稍后都会有自己的图像,但在我的代码中,我只是使用相同的图像进行测试,如果你认为这是我的问题,有没有更好的方法更快地加载这些图像?没有CSS也一样,因为slow只需等待4秒钟即可加载所有产品并在屏幕上显示;/谢谢大家!@mipa你帮我弄明白是什么让我的应用程序变慢了!我删除了背景图像,它从4秒优化到1秒左右!但是有没有更快的方法来加载图像,因为我希望每个按钮都有自己的图像?这不是问题的答案。如果你需要让OP澄清一些事情,请将其作为评论而不是答案发布。关于背景图像:每个产品(按钮)稍后都会有自己的图像,但在我的代码中,我只是使用相同的图像进行测试,如果你认为这是我的问题,有没有更好的方法更快地加载这些图像?没有CSS也一样,因为slow只需等待4秒钟即可加载所有产品并在屏幕上显示;/谢谢大家!@mipa你帮我弄明白是什么让我的应用程序变慢了!我删除了背景图像,它从4秒优化到1秒左右!但是有没有更快的方法来加载图像,因为我希望每个按钮都有自己的图像?
private void initProducts(GridPane grid, int rows, String category, Executor executor, ProductDao accessor) {
    Task<Products> productsResultTask = new Task<Products>() {
        @Override
        protected Products call() throws Exception {
            return accessor.getByCategory(category);
        }
    };

    productsResultTask.setOnFailed(e -> productsResultTask.getException().printStackTrace());

    productsResultTask.setOnSucceeded(e -> {
        if (productsResultTask.getValue() != null) {
            ArrayList<Product> products = productsResultTask.getValue().getProducts();
            int productCounter = 0;
            if (rows == 1) {
                for (int j = 0; j < products.size(); j++) {
                    initializeButton(category, products.get(productCounter), grid, 0, j);
                    initializedProducts.add(products.get(productCounter));
                    productCounter++;
                }
            } else {
                if (isEven(products.size())) {
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < products.size() / 2; j++) {
                            initializeButton(category, products.get(productCounter), grid, i, j);
                            initializedProducts.add(products.get(productCounter));
                            productCounter++;
                        }
                    }
                } else {
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < (products.size()-1) / 2; j++) {
                            initializeButton(category, products.get(productCounter), grid, i, j);
                            initializedProducts.add(products.get(productCounter));
                            productCounter++;
                        }
                    }
                    initializeButton(category, products.get(productCounter), grid, 0, ((products.size() - 1) / 2));
                    initializedProducts.add(products.get(productCounter));
                }
            }
        } else {
            System.out.println("Can't fetch products from DB!");
        }
    });
    executor.execute(productsResultTask);
}
private void initializeButton(String category, Product product, GridPane grid, int i, int j) {
        Label bName = new Label(product.getName());
        bName.setStyle("-fx-font-size: 16;");
        bName.setPrefWidth(130);
        bName.setWrapText(true);
        bName.setStyle("-fx-text-alignment: center;");
        bName.setAlignment(Pos.CENTER);

        Button button = new Button();
        button.setPrefHeight(110);
        button.setPrefWidth(130);

        BackgroundImage backgroundImage = new BackgroundImage(new Image(getClass().getResource("/images/burgerm.png").toExternalForm()),
                BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, new BackgroundSize(120, 100, false, false, false, false));
        Background background = new Background(backgroundImage);
        button.setBackground(background);
        button.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);");
        button.setOnAction(event -> {
            if (category.equals("TOPLI JADENJA")) {
                askForDrink(product);
            } else {
                addToReceipt(product);
            }

        });

        VBox item = new VBox();
        item.getChildren().addAll(button, bName);
        item.setAlignment(Pos.TOP_CENTER);
        item.setSpacing(-8);
        item.setPrefWidth(110);
        grid.add(item, j, i);
    }