Java中带复选框的树(Java CheckBox Tree)的实现和应用

在使用Java Swing开发UI程序时,很有可能会遇到使用带复选框的树的需求,但是Java Swing并没有提供这个组件,因此如果你有这个需求,你就得自己动手实现带复选框的树。

CheckBoxTree与JTree在两个层面上存在差异:

  1. 在模型层上,CheckBoxTree的每个结点需要一个成员来保存其是否被选中,但是JTree的结点则不需要。
  2. 在视图层上,CheckBoxTree的每个结点比JTree的结点多显示一个复选框。
既然存在两个差异,那么只要我们把这两个差异部分通过自己的实现填补上,那么带复选框的树也就实现了。
现在开始解决第一个差异。为了解决第一个差异,需要定义一个新的结点类CheckBoxTreeNode,该类继承DefaultMutableTreeNode,并增加新的成员isSelected来表示该结点是否被选中。对于一颗CheckBoxTree,如果某一个结点被选中的话,其复选框会勾选上,并且使用CheckBoxTree的动机在于可以一次性地选中一颗子树。那么,在选中或取消一个结点时,其祖先结点和子孙结点应该做出某种变化。在此,我们应用如下递归规则:
  1. 如果某个结点被手动选中,那么它的所有子孙结点都应该被选中;如果选中该结点使其父节点的所有子结点都被选中,则选中其父结点。
  2. 如果某个结点被手动取消选中,那么它的所有子孙结点都应该被取消选中;如果该结点的父结点处于选中状态,则取消选中其父结点。
注意:上面的两条规则是递归规则,当某个结点发生变化,导致另外的结点发生变化时,另外的结点也会导致其他的结点发生变化。在上面两条规则中,强调手动,是因为手动选中或者手动取消选中一个结点,会导致其他结点发生非手动的选中或者取消选中,这种非手动导致的选中或者非取消选中则不适用于上述规则。
按照上述规则实现的CheckBoxTreeNode源代码如下:
  1. package demo; 
  2.  
  3. import javax.swing.tree.DefaultMutableTreeNode; 
  4.  
  5. public class CheckBoxTreeNodeextends DefaultMutableTreeNode 
  6.     protected boolean isSelected; 
  7.      
  8.     public CheckBoxTreeNode() 
  9.     { 
  10.         this(null); 
  11.     } 
  12.      
  13.     public CheckBoxTreeNode(Object userObject) 
  14.     { 
  15.         this(userObject, true,false); 
  16.     } 
  17.      
  18.     public CheckBoxTreeNode(Object userObject,boolean allowsChildren, boolean isSelected) 
  19.     { 
  20.         super(userObject, allowsChildren); 
  21.         this.isSelected = isSelected; 
  22.     } 
  23.  
  24.     public boolean isSelected() 
  25.     { 
  26.         return isSelected; 
  27.     } 
  28.      
  29.     public void setSelected(boolean _isSelected) 
  30.     { 
  31.         this.isSelected = _isSelected; 
  32.          
  33.         if(_isSelected) 
  34.         { 
  35.             // 如果选中,则将其所有的子结点都选中 
  36.             if(children !=null
  37.             { 
  38.                 for(Object obj : children) 
  39.                 { 
  40.                     CheckBoxTreeNode node = (CheckBoxTreeNode)obj; 
  41.                     if(_isSelected != node.isSelected()) 
  42.                         node.setSelected(_isSelected); 
  43.                 } 
  44.             } 
  45.             // 向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中 
  46.             CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent; 
  47.             // 开始检查pNode的所有子节点是否都被选中 
  48.             if(pNode != null
  49.             { 
  50.                 int index =0
  51.                 for(; index < pNode.children.size(); ++ index) 
  52.                 { 
  53.                     CheckBoxTreeNode pChildNode = (CheckBoxTreeNode)pNode.children.get(index); 
  54.                     if(!pChildNode.isSelected()) 
  55.                         break
  56.                 } 
  57.                 /*
  58.                  * 表明pNode所有子结点都已经选中,则选中父结点,
  59.                  * 该方法是一个递归方法,因此在此不需要进行迭代,因为
  60.                  * 当选中父结点后,父结点本身会向上检查的。
  61.                  */ 
  62.                 if(index == pNode.children.size()) 
  63.                 { 
  64.                     if(pNode.isSelected() != _isSelected) 
  65.                         pNode.setSelected(_isSelected); 
  66.                 } 
  67.             } 
  68.         } 
  69.         else  
  70.         { 
  71.             /*
  72.              * 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的;
  73.              * 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但
  74.              * 是这时候是不需要取消子结点的。
  75.              */ 
  76.             if(children !=null
  77.             { 
  78.                 int index =0
  79.                 for(; index < children.size(); ++ index) 
  80.                 { 
  81.                     CheckBoxTreeNode childNode = (CheckBoxTreeNode)children.get(index); 
  82.                     if(!childNode.isSelected()) 
  83.                         break
  84.                 } 
  85.                 // 从上向下取消的时候 
  86.                 if(index == children.size()) 
  87.                 { 
  88.                     for(int i =0; i < children.size(); ++ i) 
  89.                     { 
  90.                         CheckBoxTreeNode node = (CheckBoxTreeNode)children.get(i); 
  91.                         if(node.isSelected() != _isSelected) 
  92.                             node.setSelected(_isSelected); 
  93.                     } 
  94.                 } 
  95.             } 
  96.              
  97.             // 向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。 
  98.             CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent; 
  99.             if(pNode != null && pNode.isSelected() != _isSelected) 
  100.                 pNode.setSelected(_isSelected); 
  101.         } 
  102.     } 
package demo;

import javax.swing.tree.DefaultMutableTreeNode;

public class CheckBoxTreeNode extends DefaultMutableTreeNode
{
	protected boolean isSelected;
	
	public CheckBoxTreeNode()
	{
		this(null);
	}
	
	public CheckBoxTreeNode(Object userObject)
	{
		this(userObject, true, false);
	}
	
	public CheckBoxTreeNode(Object userObject, boolean allowsChildren, boolean isSelected)
	{
		super(userObject, allowsChildren);
		this.isSelected = isSelected;
	}

	public boolean isSelected()
	{
		return isSelected;
	}
	
	public void setSelected(boolean _isSelected)
	{
		this.isSelected = _isSelected;
		
		if(_isSelected)
		{
			// 如果选中,则将其所有的子结点都选中
			if(children != null)
			{
				for(Object obj : children)
				{
					CheckBoxTreeNode node = (CheckBoxTreeNode)obj;
					if(_isSelected != node.isSelected())
						node.setSelected(_isSelected);
				}
			}
			// 向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中
			CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;
			// 开始检查pNode的所有子节点是否都被选中
			if(pNode != null)
			{
				int index = 0;
				for(; index < pNode.children.size(); ++ index)
				{
					CheckBoxTreeNode pChildNode = (CheckBoxTreeNode)pNode.children.get(index);
					if(!pChildNode.isSelected())
						break;
				}
				/* 
				 * 表明pNode所有子结点都已经选中,则选中父结点,
				 * 该方法是一个递归方法,因此在此不需要进行迭代,因为
				 * 当选中父结点后,父结点本身会向上检查的。
				 */
				if(index == pNode.children.size())
				{
					if(pNode.isSelected() != _isSelected)
						pNode.setSelected(_isSelected);
				}
			}
		}
		else 
		{
			/*
			 * 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的;
			 * 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但
			 * 是这时候是不需要取消子结点的。
			 */
			if(children != null)
			{
				int index = 0;
				for(; index < children.size(); ++ index)
				{
					CheckBoxTreeNode childNode = (CheckBoxTreeNode)children.get(index);
					if(!childNode.isSelected())
						break;
				}
				// 从上向下取消的时候
				if(index == children.size())
				{
					for(int i = 0; i < children.size(); ++ i)
					{
						CheckBoxTreeNode node = (CheckBoxTreeNode)children.get(i);
						if(node.isSelected() != _isSelected)
							node.setSelected(_isSelected);
					}
				}
			}
			
			// 向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。
			CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;
			if(pNode != null && pNode.isSelected() != _isSelected)
				pNode.setSelected(_isSelected);
		}
	}
}

第一个差异通过继承DefaultMutableTreeNode定义CheckBoxTreeNode解决了,接下来需要解决第二个差异。第二个差异是外观上的差异,JTree的每个结点是通过TreeCellRenderer进行显示的。为了解决第二个差异,我们定义一个新的类CheckBoxTreeCellRenderer,该类实现了TreeCellRenderer接口。CheckBoxTreeRenderer的源代码如下:
  1. package demo; 
  2.  
  3. import java.awt.Color; 
  4. import java.awt.Component; 
  5. import java.awt.Dimension; 
  6.  
  7. import javax.swing.JCheckBox; 
  8. import javax.swing.JPanel; 
  9. import javax.swing.JTree; 
  10. import javax.swing.UIManager; 
  11. import javax.swing.plaf.ColorUIResource; 
  12. import javax.swing.tree.TreeCellRenderer; 
  13.  
  14. public class CheckBoxTreeCellRendererextends JPanel implements TreeCellRenderer 
  15.     protected JCheckBox check; 
  16.     protected CheckBoxTreeLabel label; 
  17.      
  18.     public CheckBoxTreeCellRenderer() 
  19.     { 
  20.         setLayout(null); 
  21.         add(check = new JCheckBox()); 
  22.         add(label = new CheckBoxTreeLabel()); 
  23.         check.setBackground(UIManager.getColor("Tree.textBackground")); 
  24.         label.setForeground(UIManager.getColor("Tree.textForeground")); 
  25.     } 
  26.      
  27.     /**
  28.      * 返回的是一个<code>JPanel</code>对象,该对象中包含一个<code>JCheckBox</code>对象
  29.      * 和一个<code>JLabel</code>对象。并且根据每个结点是否被选中来决定<code>JCheckBox</code>
  30.      * 是否被选中。
  31.      */ 
  32.     @Override 
  33.     public Component getTreeCellRendererComponent(JTree tree, Object value, 
  34.             boolean selected,boolean expanded, boolean leaf,int row, 
  35.             boolean hasFocus) 
  36.     { 
  37.         String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus); 
  38.         setEnabled(tree.isEnabled()); 
  39.         check.setSelected(((CheckBoxTreeNode)value).isSelected()); 
  40.         label.setFont(tree.getFont()); 
  41.         label.setText(stringValue); 
  42.         label.setSelected(selected); 
  43.         label.setFocus(hasFocus); 
  44.         if(leaf) 
  45.             label.setIcon(UIManager.getIcon("Tree.leafIcon")); 
  46.         else if(expanded) 
  47.             label.setIcon(UIManager.getIcon("Tree.openIcon")); 
  48.         else 
  49.             label.setIcon(UIManager.getIcon("Tree.closedIcon")); 
  50.              
  51.         return this
  52.     } 
  53.  
  54.     @Override 
  55.     public Dimension getPreferredSize() 
  56.     { 
  57.         Dimension dCheck = check.getPreferredSize(); 
  58.         Dimension dLabel = label.getPreferredSize(); 
  59.         return new Dimension(dCheck.width + dLabel.width, dCheck.height < dLabel.height ? dLabel.height: dCheck.height); 
  60.     } 
  61.      
  62.     @Override 
  63.     public void doLayout() 
  64.     { 
  65.         Dimension dCheck = check.getPreferredSize(); 
  66.         Dimension dLabel = label.getPreferredSize(); 
  67.         int yCheck = 0
  68.         int yLabel = 0
  69.         if(dCheck.height < dLabel.height) 
  70.             yCheck = (dLabel.height - dCheck.height) / 2
  71.         else 
  72.             yLabel = (dCheck.height - dLabel.height) / 2
  73.         check.setLocation(0, yCheck); 
  74.         check.setBounds(0, yCheck, dCheck.width, dCheck.height); 
  75.         label.setLocation(dCheck.width, yLabel); 
  76.         label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height); 
  77.     } 
  78.      
  79.     @Override 
  80.     public void setBackground(Color color) 
  81.     { 
  82.         if(color instanceof ColorUIResource) 
  83.             color = null
  84.         super.setBackground(color); 
  85.     } 
package demo;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;

import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource;
import javax.swing.tree.TreeCellRenderer;

public class CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer
{
	protected JCheckBox check;
	protected CheckBoxTreeLabel label;
	
	public CheckBoxTreeCellRenderer()
	{
		setLayout(null);
		add(check = new JCheckBox());
		add(label = new CheckBoxTreeLabel());
		check.setBackground(UIManager.getColor("Tree.textBackground"));
		label.setForeground(UIManager.getColor("Tree.textForeground"));
	}
	
	/**
	 * 返回的是一个<code>JPanel</code>对象,该对象中包含一个<code>JCheckBox</code>对象
	 * 和一个<code>JLabel</code>对象。并且根据每个结点是否被选中来决定<code>JCheckBox</code>
	 * 是否被选中。
	 */
	@Override
	public Component getTreeCellRendererComponent(JTree tree, Object value,
			boolean selected, boolean expanded, boolean leaf, int row,
			boolean hasFocus)
	{
		String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);
		setEnabled(tree.isEnabled());
		check.setSelected(((CheckBoxTreeNode)value).isSelected());
		label.setFont(tree.getFont());
		label.setText(stringValue);
		label.setSelected(selected);
		label.setFocus(hasFocus);
		if(leaf)
			label.setIcon(UIManager.getIcon("Tree.leafIcon"));
		else if(expanded)
			label.setIcon(UIManager.getIcon("Tree.openIcon"));
		else
			label.setIcon(UIManager.getIcon("Tree.closedIcon"));
			
		return this;
	}

	@Override
	public Dimension getPreferredSize()
	{
		Dimension dCheck = check.getPreferredSize();
		Dimension dLabel = label.getPreferredSize();
		return new Dimension(dCheck.width + dLabel.width, dCheck.height < dLabel.height ? dLabel.height: dCheck.height);
	}
	
	@Override
	public void doLayout()
	{
		Dimension dCheck = check.getPreferredSize();
		Dimension dLabel = label.getPreferredSize();
		int yCheck = 0;
		int yLabel = 0;
		if(dCheck.height < dLabel.height)
			yCheck = (dLabel.height - dCheck.height) / 2;
		else
			yLabel = (dCheck.height - dLabel.height) / 2;
		check.setLocation(0, yCheck);
		check.setBounds(0, yCheck, dCheck.width, dCheck.height);
		label.setLocation(dCheck.width, yLabel);
		label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height);
	}
	
	@Override
	public void setBackground(Color color)
	{
		if(color instanceof ColorUIResource)
			color = null;
		super.setBackground(color);
	}
}
在CheckBoxTreeCellRenderer的实现中,getTreeCellRendererComponent方法返回的是JPanel,而不是像DefaultTreeCellRenderer那样返回JLabel,因此JPanel中的JLabel无法对选中做出反应,因此我们重新实现了一个JLabel的子类CheckBoxTreeLabel,它可以对选中做出反应,其源代码如下:
  1. package demo; 
  2.  
  3. import java.awt.Color; 
  4. import java.awt.Dimension; 
  5. import java.awt.Graphics; 
  6.  
  7. import javax.swing.Icon; 
  8. import javax.swing.JLabel; 
  9. import javax.swing.UIManager; 
  10. import javax.swing.plaf.ColorUIResource; 
  11.  
  12. public class CheckBoxTreeLabelextends JLabel 
  13.     private boolean isSelected; 
  14.     private boolean hasFocus; 
  15.      
  16.     public CheckBoxTreeLabel() 
  17.     { 
  18.     } 
  19.      
  20.     @Override 
  21.     public void setBackground(Color color) 
  22.     { 
  23.         if(color instanceof ColorUIResource) 
  24.             color = null
  25.         super.setBackground(color); 
  26.     } 
  27.      
  28.     @Override 
  29.     public void paint(Graphics g) 
  30.     { 
  31.         String str; 
  32.         if((str = getText()) !=null
  33.         { 
  34.             if(0 < str.length()) 
  35.             { 
  36.                 if(isSelected) 
  37.                     g.setColor(UIManager.getColor("Tree.selectionBackground")); 
  38.                 else 
  39.                     g.setColor(UIManager.getColor("Tree.textBackground")); 
  40.                 Dimension d = getPreferredSize(); 
  41.                 int imageOffset = 0
  42.                 Icon currentIcon = getIcon(); 
  43.                 if(currentIcon != null
  44.                     imageOffset = currentIcon.getIconWidth() + Math.max(0, getIconTextGap() -1); 
  45.                 g.fillRect(imageOffset, 0, d.width -1 - imageOffset, d.height); 
  46.                 if(hasFocus) 
  47.                 { 
  48.                     g.setColor(UIManager.getColor("Tree.selectionBorderColor")); 
  49.                     g.drawRect(imageOffset, 0, d.width -1 - imageOffset, d.height - 1); 
  50.                 } 
  51.             } 
  52.         } 
  53.         super.paint(g); 
  54.     } 
  55.      
  56.     @Override 
  57.     public Dimension getPreferredSize() 
  58.     { 
  59.         Dimension retDimension = super.getPreferredSize(); 
  60.         if(retDimension !=null
  61.             retDimension = new Dimension(retDimension.width +3, retDimension.height); 
  62.         return retDimension; 
  63.     } 
  64.      
  65.     public void setSelected(boolean isSelected) 
  66.     { 
  67.         this.isSelected = isSelected; 
  68.     } 
  69.      
  70.     public void setFocus(boolean hasFocus) 
  71.     { 
  72.         this.hasFocus = hasFocus; 
  73.     } 
package demo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource;

public class CheckBoxTreeLabel extends JLabel
{
	private boolean isSelected;
	private boolean hasFocus;
	
	public CheckBoxTreeLabel()
	{
	}
	
	@Override
	public void setBackground(Color color)
	{
		if(color instanceof ColorUIResource)
			color = null;
		super.setBackground(color);
	}
	
	@Override
	public void paint(Graphics g)
	{
		String str;
		if((str = getText()) != null)
		{
			if(0 < str.length())
			{
				if(isSelected)
					g.setColor(UIManager.getColor("Tree.selectionBackground"));
				else
					g.setColor(UIManager.getColor("Tree.textBackground"));
				Dimension d = getPreferredSize();
				int imageOffset = 0;
				Icon currentIcon = getIcon();
				if(currentIcon != null)
					imageOffset = currentIcon.getIconWidth() + Math.max(0, getIconTextGap() - 1);
				g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height);
				if(hasFocus)
				{
					g.setColor(UIManager.getColor("Tree.selectionBorderColor"));
					g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, d.height - 1);
				}
			}
		}
		super.paint(g);
	}
	
	@Override
	public Dimension getPreferredSize()
	{
		Dimension retDimension = super.getPreferredSize();
		if(retDimension != null)
			retDimension = new Dimension(retDimension.width + 3, retDimension.height);
		return retDimension;
	}
	
	public void setSelected(boolean isSelected)
	{
		this.isSelected = isSelected;
	}
	
	public void setFocus(boolean hasFocus)
	{
		this.hasFocus = hasFocus;
	}
}

通过定义CheckBoxTreeNode和CheckBoxTreeCellRenderer。我们解决了CheckBoxTree和JTree的两个根本差异,但是还有一个细节问题需要解决,就是CheckBoxTree可以响应用户事件决定是否选中某个结点。为此,我们为CheckBoxTree添加一个响应用户鼠标事件的监听器CheckBoxTreeNodeSelectionListener,该类的源代码如下:
  1. package demo; 
  2.  
  3. import java.awt.event.MouseAdapter; 
  4. import java.awt.event.MouseEvent; 
  5.  
  6. import javax.swing.JTree; 
  7. import javax.swing.tree.TreePath; 
  8. import javax.swing.tree.DefaultTreeModel; 
  9.  
  10. public class CheckBoxTreeNodeSelectionListenerextends MouseAdapter 
  11.     @Override 
  12.     public void mouseClicked(MouseEvent event) 
  13.     { 
  14.         JTree tree = (JTree)event.getSource(); 
  15.         int x = event.getX(); 
  16.         int y = event.getY(); 
  17.         int row = tree.getRowForLocation(x, y); 
  18.         TreePath path = tree.getPathForRow(row); 
  19.         if(path != null
  20.         { 
  21.             CheckBoxTreeNode node = (CheckBoxTreeNode)path.getLastPathComponent(); 
  22.             if(node != null
  23.             { 
  24.                 boolean isSelected = !node.isSelected(); 
  25.                 node.setSelected(isSelected); 
  26.                 ((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node); 
  27.             } 
  28.         } 
  29.     } 
package demo;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JTree;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultTreeModel;

public class CheckBoxTreeNodeSelectionListener extends MouseAdapter
{
	@Override
	public void mouseClicked(MouseEvent event)
	{
		JTree tree = (JTree)event.getSource();
		int x = event.getX();
		int y = event.getY();
		int row = tree.getRowForLocation(x, y);
		TreePath path = tree.getPathForRow(row);
		if(path != null)
		{
			CheckBoxTreeNode node = (CheckBoxTreeNode)path.getLastPathComponent();
			if(node != null)
			{
				boolean isSelected = !node.isSelected();
				node.setSelected(isSelected);
				((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node);
			}
		}
	}
}
到此为止,CheckBoxTree所需要的所有组件都已经完成了,接下来就是如何使用这些组件。下面给出了使用这些组件的源代码:
  1. package demo; 
  2.  
  3. import javax.swing.JFrame; 
  4. import javax.swing.JScrollPane; 
  5. import javax.swing.JTree; 
  6. import javax.swing.tree.DefaultTreeModel; 
  7.  
  8. public class DemoMain  
  9.     public staticvoid main(String[] args) 
  10.     { 
  11.         JFrame frame = new JFrame("CheckBoxTreeDemo"); 
  12.         frame.setBounds(200,200, 400,400); 
  13.         JTree tree = new JTree(); 
  14.         CheckBoxTreeNode rootNode = new CheckBoxTreeNode("root"); 
  15.         CheckBoxTreeNode node1 = new CheckBoxTreeNode("node_1"); 
  16.         CheckBoxTreeNode node1_1 = new CheckBoxTreeNode("node_1_1"); 
  17.         CheckBoxTreeNode node1_2 = new CheckBoxTreeNode("node_1_2"); 
  18.         CheckBoxTreeNode node1_3 = new CheckBoxTreeNode("node_1_3"); 
  19.         node1.add(node1_1); 
  20.         node1.add(node1_2); 
  21.         node1.add(node1_3); 
  22.         CheckBoxTreeNode node2 = new CheckBoxTreeNode("node_2"); 
  23.         CheckBoxTreeNode node2_1 = new CheckBoxTreeNode("node_2_1"); 
  24.         CheckBoxTreeNode node2_2 = new CheckBoxTreeNode("node_2_2"); 
  25.         node2.add(node2_1); 
  26.         node2.add(node2_2); 
  27.         rootNode.add(node1); 
  28.         rootNode.add(node2); 
  29.         DefaultTreeModel model = new DefaultTreeModel(rootNode); 
  30.         tree.addMouseListener(new CheckBoxTreeNodeSelectionListener()); 
  31.         tree.setModel(model); 
  32.         tree.setCellRenderer(new CheckBoxTreeCellRenderer()); 
  33.         JScrollPane scroll = new JScrollPane(tree); 
  34.         scroll.setBounds(0,0, 300,320); 
  35.         frame.getContentPane().add(scroll); 
  36.          
  37.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
  38.         frame.setVisible(true); 
  39.     } 
package demo;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;

public class DemoMain 
{
	public static void main(String[] args)
	{
		JFrame frame = new JFrame("CheckBoxTreeDemo");
		frame.setBounds(200, 200, 400, 400);
		JTree tree = new JTree();
		CheckBoxTreeNode rootNode = new CheckBoxTreeNode("root");
		CheckBoxTreeNode node1 = new CheckBoxTreeNode("node_1");
		CheckBoxTreeNode node1_1 = new CheckBoxTreeNode("node_1_1");
		CheckBoxTreeNode node1_2 = new CheckBoxTreeNode("node_1_2");
		CheckBoxTreeNode node1_3 = new CheckBoxTreeNode("node_1_3");
		node1.add(node1_1);
		node1.add(node1_2);
		node1.add(node1_3);
		CheckBoxTreeNode node2 = new CheckBoxTreeNode("node_2");
		CheckBoxTreeNode node2_1 = new CheckBoxTreeNode("node_2_1");
		CheckBoxTreeNode node2_2 = new CheckBoxTreeNode("node_2_2");
		node2.add(node2_1);
		node2.add(node2_2);
		rootNode.add(node1);
		rootNode.add(node2);
		DefaultTreeModel model = new DefaultTreeModel(rootNode);
		tree.addMouseListener(new CheckBoxTreeNodeSelectionListener());
		tree.setModel(model);
		tree.setCellRenderer(new CheckBoxTreeCellRenderer());
		JScrollPane scroll = new JScrollPane(tree);
		scroll.setBounds(0, 0, 300, 320);
		frame.getContentPane().add(scroll);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
其执行结果如下图所示:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值