树型结构是比较常规的分类思维方式,好的分类规则能事半功倍,比如文件目录、日常开发的代码,时序图是树型结构的另一种展示形式。这里介绍插件中JTree的基本结构。
JTree对象生成及配置
/** * 配置树对象 * * @param tree this.tree = new JXTree(); * @param treePanel treePanel = new JScrollPane(); 滑动对象 * @param rootVisible 是否展示根节点 */ public static void configTree(JTree tree, JScrollPane treePanel, boolean rootVisible) { // tree 配置 DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); model.setRoot(new DefaultMutableTreeNode()); // 渲染树节点对象 tree.setCellRenderer(new MTTreeCellRenderer()); // 根节点不展示 tree.setRootVisible(rootVisible); // true 或 false 决策根节点左上角折号是否展示 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 树所属的对象,一般用于树操作时需要数据传递 */ public static void addTreeEvent(JTree tree, TreePanelMark treeContext) { // 树节点被选中时 tree.addTreeSelectionListener(e -> { DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (null == mutableTreeNode || !(mutableTreeNode.getUserObject() instanceof MTTreeCell)) { return; } ((MTTreeCell) mutableTreeNode.getUserObject()).treeSelectionListener(tree, mutableTreeNode, treeContext); }); // 树节被点击,单击、双击 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递归包装成树节点
一般是 一个 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; } /** * 递归遍历数据结构生成树节点 * * @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展开、收起树节点
/** * 展开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重新加载
当子节点变化后需要重新加载已经变化的子节点
/** * 重新加载 * * @param jTree * @param node 变化的子节点的父节点 */ public static void reload(JTree jTree, DefaultMutableTreeNode node) { ((DefaultTreeModel) jTree.getModel()).reload(node); }
JTree 渲染对象 Renderer
public class MTTreeCellRenderer extends ColoredTreeCellRenderer { /** * 渲染每个节点 * * @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()); } } }}