簡體   English   中英

手動展開/折疊所有樹項 memory 成本 javafx 2.2

[英]Manually expand/collapse all treeitems memory cost javafx 2.2

我正在使用 Netbeans 7.2 開發一個 JavaFX 2.2 應用程序。 我正在使用 treeview 並擴展了 TreeCell 以向每個 TreeItem 提供一個上下文菜單,其中的 MenuItem 具有“Collpase All”功能。 treeview 的最大深度級別為 4。當用戶右鍵單擊級別 2 的 TreeItem 並單擊“全部折疊”菜單項時,我想讓級別 3 的所有 TreeItem 折疊 (setExpanded(false))。 您可以在下面看到我正在使用的代碼。 我的問題是這個操作的 memory 和 CPU 成本。 我在第 3 級插入了 250 個 TreeItem。每次 collapseAll 單擊時,一次 collapse all 操作的成本約為 200MB memory,花費大約 2s 的時間。 我的開發者計算機的 CPU 是 Intel i5 (3.3GHz),我有 8GB 的 memory? 這些硬件成本是正常的還是我的代碼有問題? 我是否使用了錯誤的方式來折疊它們?

這個 class 管理 TreeView。從數據庫加載數據,重新加載它們,了解所選的 TreeItem 並展開/折疊所選的子 TreeItem。

public final class TargetTree extends SqlConnectionManager {

    private TreeView tree;
    private TreeItem selectedItem;

    private TargetTree() {
        super();
        this.tree = null;
        this.selectedItem = null;
    }

    private TargetTree(TreeView tree) {
        super();
        this.tree = tree;
        this.selectedItem = null;
    }

    public static TargetTree construct(TreeView tree) {
        if (tree == null) {
            return null;
        }

        TargetTree targetTree = new TargetTree(tree);
        targetTree.load();
        return targetTree;
    }

    public void reload() {
        // Clear current tree.
        if (tree.getRoot() != null) {
            for (int i = 0; i < tree.getRoot().getChildren().size(); i++) {
                tree.getRoot().getChildren().clear();
            }
            tree.setRoot(null);
        }
        this.load();
    }

    public void prune() {
        //TODO
    }

    private void load() {
        // New root Item.
        final TreeItem<Object> treeRoot = new TreeItem<>((Object) "Root");
        treeRoot.setExpanded(true);

        // This integers help to find when to build a new department/section/measure.
        int lastDepartmentId = -1;
        int lastSectionId = -1;
        int lastMeasureId = -1;
        int lastTargetId = -1;

        //The temp treeitems.
        TreeItem<Object> departmentTreeItem = null;
        TreeItem<Object> sectionTreeItem = null;
        TreeItem<Object> measureTreeItem = null;
        TreeItem<Object> targetTreeItem = null;

        // Get the new TreeItems from the database.
        super.errorMessage = "";
        try {
            // Establishing connection with db.
            super.openConnection();

            // Query to be executed. Selects everything from the database.
            preparedStmt = connection.prepareStatement(
                    "SELECT.....ORDER BY....;");
            resultSet = preparedStmt.executeQuery();

            while (resultSet.next()) {
                // Department Creation.
                if (lastDepartmentId != resultSet.getInt("departmentId")) {
                    final Department department = Department.initEmpty();
                    department.setId(resultSet.getInt("departmentId"));
                    department.setName(resultSet.getString("departmentName"));

                    // Create the treeitem for this department.
                    departmentTreeItem = new TreeItem<>((Object) department);
                    departmentTreeItem.setExpanded(true);
                    treeRoot.getChildren().add(departmentTreeItem);

                    // Reset the children ids to ensure that they will be recreated.
                    lastDepartmentId = resultSet.getInt("departmentId");
                    lastSectionId = -1;
                    lastMeasureId = -1;
                    lastTargetId = -1;
                }

                // Section Creation.
                if (lastSectionId != resultSet.getInt("sectionId")) {
                    final Section section = Section.initEmpty();
                    section.setId(resultSet.getInt("sectionId"));
                    section.setName(resultSet.getString("sectionName"));

                    // Create the treeitem for this section.
                    sectionTreeItem = new TreeItem<>((Object) section);
                    sectionTreeItem.setExpanded(true);
                    departmentTreeItem.getChildren().add(sectionTreeItem);

                    // Reset the children ids to ensure that they will be recreated.
                    lastSectionId = resultSet.getInt("sectionId");
                    lastMeasureId = -1;
                    lastTargetId = -1;
                }

                // Measure Creation.
                if (lastMeasureId != resultSet.getInt("measureId")) {
                    final Measure measure = Measure.initEmpty();
                    measure.setId(resultSet.getInt("measureId"));
                    measure.setLastname(resultSet.getString("measureLastname"));
                    measure.setFirstname(resultSet.getString("measureFirstName"));

                    // Create the treeitem for this measure.
                    measureTreeItem = new TreeItem<>((Object) measure);
                    measureTreeItem.setExpanded(true);
                    sectionTreeItem.getChildren().add(measureTreeItem );

                    // Reset the children ids to ensure that they will be recreated.
                    lastMeasureId = resultSet.getInt("measureId");
                    lastTargetId = -1;
                }

                // Target Creation.
                if (lastTargetId != resultSet.getInt("targetId")) {
                    final Target target = Target.initEmpty();
                    target.setId(resultSet.getInt("targetId"));
                    target.setText(resultSet.getString("targetText"));

                    // Create the treeitem for this target.
                    targetTreeItem = new TreeItem<>((Object) target);
                    targetTreeItem.setExpanded(false);
                    measureTreeItem.getChildren().add(targetTreeItem);

                    // Reset the children ids to ensure that they will be recreated.
                    lastTargetId = resultSet.getInt("targetId");
                }
            }

            closeAll();
        } catch (SQLException ex) {
            super.errorMessage = ex.getMessage();
        }

        tree.setRoot(treeRoot);
        final TargetTree targetTree = this;
        tree.setCellFactory(new Callback<TreeView<Object>, TreeCell<Object>>() {
            @Override
            public TreeCell<Object> call(TreeView<Object> p) {
                return new TargetTreeCell(targetTree);
            }
        });

        // Select a Tree Item.
        tree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                selectedItem = (TreeItem) newValue;
            }
        });
    }

    public void collapseChildren() {
        Thread thread = new Thread(new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < selectedItem.getChildren().size(); i++) {
                            TreeItem<Object> current = (TreeItem<Object>) selectedItem.getChildren().get(i);
                            if (!current.isLeaf()) {
                                current.setExpanded(false);
                            }
                            current = null;
                        }
                        selectedItem.setExpanded(false);
                        System.gc();
                    }
                });
                return null;
            }
        });
        thread.setDaemon(true);
        thread.start();
    }

    public void expandChildren() {
        Thread thread = new Thread(new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < selectedItem.getChildren().size(); i++) {
                            TreeItem<Object> current = (TreeItem<Object>) selectedItem.getChildren().get(i);
                            if (!current.isLeaf()) {
                                current.setExpanded(true);
                            }
                            current = null;
                        }
                        selectedItem.setExpanded(true);
                        System.gc();
                    }
                });
                return null;
            }
        });
        thread.setDaemon(true);
        thread.start();
    }
}

下面是自定義的 TreeCell class。

public class TargetTreeCell extends TreeCell<Object> {

    private TargetTree targetTree;

    public TargetTreeCell(TargetTree targetTree) {
        super();
        this.targetTree = targetTree;
    }

    @Override
    public void updateItem(Object item, boolean empty) {
        super.updateItem(item, empty);

        if (item != null) {
            if (item instanceof Target) {
                initTarget(item);
            } else if (item instanceof Measure) {
                initMeasure(item);
            } else if (item instanceof Section) {
                initSection(item);
            } else if (item instanceof Department) {
                initDepartment(item);
            } else if (item instanceof String) {
                initRoot(item);
            }
        }
    }

    ///<editor-fold defaultstate="collapsed" desc="Tree Item Initialization">
    private void initRoot(Object item) {
        // Create Menu Items.
        MenuItem expandAllMenuItems = new MenuItem("Expand All");
        MenuItem collapseAllMenuItems = new MenuItem("Collapse All");

        // Event Haddlers for each Menu Items.
        expandAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
            }
        });
        collapseAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.collapseChildren();
            }
        });

        // Create Menu and add Menu Items.
        ContextMenu contextMenu = new ContextMenu();
        contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);

        //Init Root Tree Item.
        String root = (String) item;
        setText(root);
        setContextMenu(contextMenu);
    }

    private void initDepartment(Object item) {
        // Create Menu Items.
        MenuItem expandAllMenuItems = new MenuItem("Expand All");
        MenuItem collapseAllMenuItems = new MenuItem("Collapse All");

        // Event Haddlers for each Menu Items.
        expandAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.expandChildren();
            }
        });
        collapseAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.collapseChildren();
            }
        });

        // Create Menu and add Menu Items.
        ContextMenu contextMenu = new ContextMenu();
        contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);

        //Init Department Tree Item.
        Department department = (Department) item;
        setText(department.getName());
        setContextMenu(contextMenu);
    }

    private void initSection(Object item) {
        // Create Menu Items.
        MenuItem expandAllMenuItems = new MenuItem("Expand All");
        MenuItem collapseAllMenuItems = new MenuItem("Collapse All");

        // Event Haddlers for each Menu Items.
        expandAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.expandChildren();
            }
        });
        collapseAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.collapseChildren();
            }
        });

        // Create Menu and add Menu Items.
        ContextMenu contextMenu = new ContextMenu();
        contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);

        //Init Section Tree Item.
        Section section = (Section) item;
        setText(section.getName());
        setContextMenu(contextMenu);
    }

    private void initMeasure(Object item) {
        // Create Menu Items.
        MenuItem expandAllMenuItems = new MenuItem("Expand");
        MenuItem collapseAllMenuItems = new MenuItem("Collapse");

        // Event Haddlers for each Menu Items.
        expandAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.expandChildren();
            }
        });
        collapseAllMenuItems.setOnAction(new EventHandler() {
            @Override
            public void handle(Event event) {
                targetTree.collapseChildren();
            }
        });

        // Create Menu and add Menu Items.
        ContextMenu contextMenu = new ContextMenu();
        contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);

        //Init Section Tree Item.
        Measure measure = (Measure) item;
        setText(measure.getLastname() + " " + measure.getFirstname());
        setContextMenu(contextMenu);
    }

    private void initTarget(Object item) {
        //Init Section Tree Item.
        Target target = (Target) item;
        setText(target.getText());
    }
    ///</editor-fold>
}

如果我有復制粘貼錯誤請原諒我..我編譯沒有問題。 代碼運行沒有錯誤。 我的問題出在第一個 class 的方法 expandChildren() 和 collapseChildren() 上。在以前的版本中,我沒有使用線程,而是使用遞歸來使所有子 TreeItems(及其子 TreeItems..)崩潰,但是memory 成本更高。

我找到了問題的答案! 我將用一個例子來解釋。 我用100個TreeItems初始化一個TreeView,結果是一個具有3個級別的樹結構。 在屏幕上,樹只顯示了其中的45個。 要查看其他項目,我必須向上/向下滾動或展開折疊的TreeItems。 在每種情況下,都會調用方法updateItem來構造新的TreeItem,這些新的TreeItem將在屏幕樹上顯示為可見,因此它們都出現在屏幕上。

當我折疊展開的TreeItem時,updateItem方法將運行。 這就是內存和CPU成本的原因! 我不得不折疊〜總共200個TreeItem,然后它們的父級展開了。

我用一種非常簡單的方法解決了我的問題。 在我開始折疊所有內容之前,我折疊了父級TreeItem。 因此,我首先讓父母崩潰,然后讓所有孩子崩潰。 從源代碼(setExpanded(false))逐一折疊子項時,由於子項的父項和子項TreeItem在屏幕中不存在,因此updateItem方法未運行。

通過這種方式,我節省了很多內存和CPU時間,而我像一個虛擬人一樣度過。

我犯了同樣的錯誤,發生在我實施 MenuItem 以完全折疊整個 TreeItems(當前選擇作為父項)子分支時。 但是 collapse 方法將選擇清除為減一 (-1),並且該更改不可見,因為它之后沒有刷新父項單元格。 所以乍一看似乎沒有任何變化,因為焦點仍然在同一行上可見。 我想需要清除皮膚選擇器才能折疊子項,或者接管選擇索引。 所以首先折疊父項,所有子項都應該折疊,然后重置選擇索引,然后再次展開父項。 非常感謝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM