樹型結構是比較常規(guī)的分類思維方式,好的分類規(guī)則能事半功倍,比如文件目錄、日常開發(fā)的代碼,時序圖是樹型結構的另一種展示形式。這里介紹插件中JTree的基本結構。
JTree對象生成及配置
/** * 配置樹對象 * * @param tree this.tree = new JXTree(); * @param treePanel treePanel = new JScrollPane(); 滑動對象 * @param rootVisible 是否展示根節(jié)點 */ public static void configTree(JTree tree, JScrollPane treePanel, boolean rootVisible) { // tree 配置 DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); model.setRoot(new DefaultMutableTreeNode()); // 渲染樹節(jié)點對象 tree.setCellRenderer(new MTTreeCellRenderer()); // 根節(jié)點不展示 tree.setRootVisible(rootVisible); // true 或 false 決策根節(jié)點左上角折號是否展示 tree.setShowsRootHandles(true); treePanel.setViewportView(tree); // 快速搜索 new TreeSpeedSearch(tree); // 用于loading的關鍵配置 ComponentUtil.putClientProperty(tree, ANIMATION_IN_RENDERER_ALLOWED, true); ComponentUtil.putClientProperty(tree, AUTO_EXPAND_ALLOWED, false); ComponentUtil.putClientProperty(tree, SHRINK_LONG_RENDERER, true); }
JTree事件包裝
/** * @param tree * @param treeContext 樹所屬的對象,一般用于樹操作時需要數(shù)據(jù)傳遞 */ public static void addTreeEvent(JTree tree, TreePanelMark treeContext) { // 樹節(jié)點被選中時 tree.addTreeSelectionListener(e -> { DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (null == mutableTreeNode || !(mutableTreeNode.getUserObject() instanceof MTTreeCell)) { return; } ((MTTreeCell) mutableTreeNode.getUserObject()).treeSelectionListener(tree, mutableTreeNode, treeContext); }); // 樹節(jié)被點擊,單擊、雙擊 tree.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { final int doubleClick = 2; if (e.getClickCount() >= doubleClick) { DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (null == mutableTreeNode || !(mutableTreeNode.getUserObject() instanceof MTTreeCell)) { return; } ((MTTreeCell) mutableTreeNode.getUserObject()).doubleClick(tree, mutableTreeNode, treeContext); } } } /** * 右鍵菜單 */ @Override public void mouseReleased(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e)) { TreePath path = tree.getPathForLocation(e.getX(), e.getY()); tree.setSelectionPath(path); DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (null == mutableTreeNode || !(mutableTreeNode.getUserObject() instanceof MTTreeCell)) { return; } ((MTTreeCell) mutableTreeNode.getUserObject()).rightClick(tree, mutableTreeNode, e, treeContext); } } }); // 按回車鍵跳轉到對應方法 tree.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { super.keyPressed(e); if (e.getKeyCode() == KeyEvent.VK_ENTER) { DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (null == mutableTreeNode || !(mutableTreeNode.getUserObject() instanceof MTTreeCell)) { return; } ((MTTreeCell) mutableTreeNode.getUserObject()).keyEnter(tree, mutableTreeNode, treeContext); } } }); }
JTree遞歸包裝成樹節(jié)點
一般是 一個 userObject 對應一個 DefaultMutableTreeNode,樹型關系由 DefaultMutableTreeNode 來維護,后面刪除、添加、上移、下移方便處理。
/** * 渲染遍歷樹 * * @param tree * @param rootTreeCell */ public static DefaultMutableTreeNode renderRepeaterTree(JTree tree, MTTreeCell rootTreeCell) { if (null == rootTreeCell) { return null; } DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootTreeCell); renderRepeaterTreeSub(rootTreeCell.subTreeCell(), root); DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); model.setRoot(root); expandOrCollapAll(tree, new TreePath(tree.getModel().getRoot()), true); return root; } /** * 遞歸遍歷數(shù)據(jù)結構生成樹節(jié)點 * * @param subTreeCells * @param parentNode */ public static void renderRepeaterTreeSub(List<MTTreeCell> subTreeCells, DefaultMutableTreeNode parentNode) { if (CollectionUtils.isEmpty(subTreeCells)) { return; } for (MTTreeCell subTreeCell : subTreeCells) { DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(subTreeCell); parentNode.add(treeNode); renderRepeaterTreeSub(subTreeCell.subTreeCell(), treeNode); } }
JTree展開、收起樹節(jié)點
/** * 展開tree視圖 * * @param parent treePath * @param expand 是否展開 */ public static void expandOrCollapAll(@NotNull JTree tree, @NotNull TreePath parent, boolean expand) { TreeNode node = (TreeNode) parent.getLastPathComponent(); if (node.getChildCount() >= 0) { for (Enumeration<?> e = node.children(); e.hasMoreElements(); ) { TreeNode n = (TreeNode) e.nextElement(); TreePath path = parent.pathByAddingChild(n); expandOrCollapAll(tree, path, expand); } } // 展開或收起必須自下而上進行 if (expand) { tree.expandPath(parent); } else { tree.collapsePath(parent); } }
JTree重新加載
當子節(jié)點變化后需要重新加載已經(jīng)變化的子節(jié)點
/** * 重新加載 * * @param jTree * @param node 變化的子節(jié)點的父節(jié)點 */ public static void reload(JTree jTree, DefaultMutableTreeNode node) { ((DefaultTreeModel) jTree.getModel()).reload(node); }
JTree 渲染對象 Renderer
public class MTTreeCellRenderer extends ColoredTreeCellRenderer { /** * 渲染每個節(jié)點 * * @param tree * @param value * @param selected * @param expanded * @param leaf * @param row * @param hasFocus */ @Override public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { Object obj = ((DefaultMutableTreeNode) value).getUserObject(); if (obj instanceof MTTreeCell) { MTTreeCell node = (MTTreeCell) obj; Icon loadingIcon = node.loadingIcon(); if (null != loadingIcon) { setIcon(loadingIcon); } else if (null != node.selfControlSelect()) { if (node.selfControlSelect()) { setIcon(node.iconSelected()); } else { setIcon(node.iconUnselected()); } } else { if (selected) { if (null != node.iconSelected()) { setIcon(node.iconSelected()); } } else { if (null != node.iconUnselected()) { setIcon(node.iconUnselected()); } } } if (null == node.fontAttributes()) { Append(node.cellShow()); } else { append(node.cellShow(), node.fontAttributes()); } } }}