一个简单的CheckBox Tree实现
CheckBox Tree是一个十分常用的UI组件,它能使用户方便地按特定规则勾选树中的节点。本文实现了一种简单的Checking规则:当勾选了某节点后,该节点的所有下级节点全部被勾选;当取消勾选某节点后,该节点的所有下级节点全部被取消勾选。(2009.08.05最后更新)
实现CheckBox Tree的常用方法,就是使用JCheckBox作为JTree的TreeCellRendrer,并且需要实现特定的Checking规则来勾选/取消勾选CheckBox。
1. 树节点
DefaultMutableTreeNode是最常用的TreeNode实现,此处我们将扩展这一实现--CheckBoxTreeNode,增加一个属性isChecked,用于标识该节点是否要被勾选上。该类的完整代码如下所示:
public class CheckBoxTreeNode extends DefaultMutableTreeNode {
       private static final long serialVersionUID = 3195314943599939279L;
       private boolean isChecked = false;
       public CheckBoxTreeNode(Object userObject) {
               super(userObject);
       }
       public boolean isChecked() {
               return isChecked;
       }
       public void setChecked(boolean isChecked) {
               this.isChecked = isChecked;
       }
}
2. 渲染器
如本文开头所述,我们将使用JCheckBox作为树节点展现形式的渲染器,同时确定对节点进行勾选或取消勾选的规则。CheckBoxTreeCellRenderer本身即是一个JCheckBox,那么在实现getTreeCellRendererComponent方法时,只简单地返回它自己的实例即可,而对于勾选或取消勾选的条件,则由CheckBoxTreeNode中的isChecked属性来确定,完整的代码如下所示:
public class CheckBoxTreeCellRenderer extends JCheckBox implements TreeCellRenderer {
       private static final long serialVersionUID = -6432020851855339311L;
       public CheckBoxTreeCellRenderer() {
               setOpaque(false);
       }
       public Component getTreeCellRendererComponent(JTree tree, Object value,
                       boolean selected, boolean expanded, boolean leaf, int row,
                       boolean hasFocus) {
               CheckBoxTreeNode node = ((CheckBoxTreeNode) value); // 获取树节点对象。
               setText(node.toString()); // 设置CheckBox所展示的文本。
               // 当树节点被设置为勾选时,则该节点对应的CheckBox被勾选上;否则,取消勾选。
               if (node.isChecked()) {
                       setSelected(true);
                       setForeground(Color.BLUE);
               } else {
                       setSelected(false);
                       setForeground(tree.getForeground());
               }
               return this;
       }
}
3. 树
此处对JTree进行扩展,创建CheckBoxTree,该类只是为JTree添加了一个MouseListener,以侦听鼠标选中树节点后,如何设置勾选标记,并重绘树。
public class CheckBoxTree extends JTree {
       private static final long serialVersionUID = -217950037507321241L;
       public CheckBoxTree(TreeModel newModel) {
               super(newModel);
               addCheckingListener();
       }
       private void addCheckingListener() {
               addMouseListener(new MouseAdapter() {
                       @Override
                       public void mousePressed(MouseEvent e) {
                               int row = getRowForLocation(e.getX(), e.getY());
                               TreePath treePath = getPathForRow(row);
                               if (treePath == null) {
                                       return;
                               }
                               CheckBoxTreeNode node = ((CheckBoxTreeNode) treePath.getLastPathComponent());
                               boolean checking = !node.isChecked(); // 如果该节点已被勾选上,则此次将取消勾选;反之,亦反。
                               checkNode(node, checking);
                               repaint(); // 重绘整棵树。
                       }
                       // 递归地勾选或取消勾选指定节点及其所有下级节点的CheckBox。
                       private void checkNode(CheckBoxTreeNode node, boolean checking) {
                               node.setChecked(checking);
                               if (!node.isLeaf()) {
                                       Enumeration<CheckBoxTreeNode> children = node.children();
                                       while (children.hasMoreElements()) {
                                               checkNode(children.nextElement(), checking);
                                       }
                               }
                       }
               });
       }
}
上述程序有两个关键点:1. 设置当前节点及其子节点的勾选标记--checkNode;2. 重绘树--repaint。调用repaint方法对树进行绘制时,方法TreeCellRenderer.getTreeCellRendererComponent就会被调用,此时程序就会根据checkNode方法设定的isChecked来勾选或取消勾选对应的树节点CheckBox。简言之,就是先设置树型数据中的勾选标记,然后渲染器再根据这些标记来渲染CheckBox。