自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java中帶復(fù)選框的樹的實現(xiàn)和應(yīng)用

開發(fā) 后端
在使用Java Swing開發(fā)UI程序時,很有可能會遇到使用帶復(fù)選框的樹的需求,但是Java Swing并沒有提供這個組件,因此如果你有這個需求,你就得自己動身實現(xiàn)帶復(fù)選框的樹。

在使用Java Swing開發(fā)UI程序時,很有可能會遇到使用帶復(fù)選框的樹的需求,但是Java Swing并沒有提供這個組件,因此如果你有這個需求,你就得自己動身實現(xiàn)帶復(fù)選框的樹。

CheckBoxTree與JTree在兩個層面上存在差異:

  1. 在模型層上,CheckBoxTree的每個結(jié)點(diǎn)需要一個成員來保存其是否被選中,但是JTree的結(jié)點(diǎn)則不需要。
  2. 在視圖層上,CheckBoxTree的每個結(jié)點(diǎn)比JTree的結(jié)點(diǎn)多顯示一個復(fù)選框。

既然存在兩個差異,那么只要我們把這兩個差異部分通過自己的實現(xiàn)填補(bǔ)上,那么帶復(fù)選框的樹也就實現(xiàn)了。

現(xiàn)在開始解決第一個差異。為了解決第一個差異,需要定義一個新的結(jié)點(diǎn)類CheckBoxTreeNode,該類繼承DefaultMutableTreeNode,并增加新的成員isSelected來表示該結(jié)點(diǎn)是否被選中。對于一顆CheckBoxTree,如果某一個結(jié)點(diǎn)被選中的話,其復(fù)選框會勾選上,并且使用CheckBoxTree的動機(jī)在于可以一次性地選中一顆子樹。那么,在選中或取消一個結(jié)點(diǎn)時,其祖先結(jié)點(diǎn)和子孫結(jié)點(diǎn)應(yīng)該做出某種變化。在此,我們應(yīng)用如下遞歸規(guī)則:

  1. 如果某個結(jié)點(diǎn)被手動選中,那么它的所有子孫結(jié)點(diǎn)都應(yīng)該被選中;如果選中該結(jié)點(diǎn)使其父節(jié)點(diǎn)的所有子結(jié)點(diǎn)都被選中,則選中其父結(jié)點(diǎn)。
  2. 如果某個結(jié)點(diǎn)被手動取消選中,那么它的所有子孫結(jié)點(diǎn)都應(yīng)該被取消選中;如果該結(jié)點(diǎn)的父結(jié)點(diǎn)處于選中狀態(tài),則取消選中其父結(jié)點(diǎn)。

注意:上面的兩條規(guī)則是遞歸規(guī)則,當(dāng)某個結(jié)點(diǎn)發(fā)生變化,導(dǎo)致另外的結(jié)點(diǎn)發(fā)生變化時,另外的結(jié)點(diǎn)也會導(dǎo)致其他的結(jié)點(diǎn)發(fā)生變化。在上面兩條規(guī)則中,強(qiáng)調(diào)手動,是因為手動選中或者手動取消選中一個結(jié)點(diǎn),會導(dǎo)致其他結(jié)點(diǎn)發(fā)生非手動的選中或者取消選中,這種非手動導(dǎo)致的選中或者非取消選中則不適用于上述規(guī)則。

按照上述規(guī)則實現(xiàn)的CheckBoxTreeNode源代碼如下:

  1. package demo;  
  2.  
  3. import javax.swing.tree.DefaultMutableTreeNode;  
  4.  
  5. public class CheckBoxTreeNode extends DefaultMutableTreeNode  
  6. {  
  7.     protected boolean isSelected;  
  8.       
  9.     public CheckBoxTreeNode()  
  10.     {  
  11.         this(null);  
  12.     }  
  13.       
  14.     public CheckBoxTreeNode(Object userObject)  
  15.     {  
  16.         this(userObject, truefalse);  
  17.     }  
  18.       
  19.     public CheckBoxTreeNode(Object userObject, boolean allowsChildren, boolean isSelected)  
  20.     {  
  21.         super(userObject, allowsChildren);  
  22.         this.isSelected = isSelected;  
  23.     }  
  24.  
  25.     public boolean isSelected()  
  26.     {  
  27.         return isSelected;  
  28.     }  
  29.       
  30.     public void setSelected(boolean _isSelected)  
  31.     {  
  32.         this.isSelected = _isSelected;  
  33.           
  34.         if(_isSelected)  
  35.         {  
  36.             // 如果選中,則將其所有的子結(jié)點(diǎn)都選中  
  37.             if(children != null)  
  38.             {  
  39.                 for(Object obj : children)  
  40.                 {  
  41.                     CheckBoxTreeNode node = (CheckBoxTreeNode)obj;  
  42.                     if(_isSelected != node.isSelected())  
  43.                         node.setSelected(_isSelected);  
  44.                 }  
  45.             }  
  46.             // 向上檢查,如果父結(jié)點(diǎn)的所有子結(jié)點(diǎn)都被選中,那么將父結(jié)點(diǎn)也選中  
  47.             CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;  
  48.             // 開始檢查pNode的所有子節(jié)點(diǎn)是否都被選中  
  49.             if(pNode != null)  
  50.             {  
  51.                 int index = 0;  
  52.                 for(; index < pNode.children.size(); ++ index)  
  53.                 {  
  54.                     CheckBoxTreeNode pChildNode = (CheckBoxTreeNode)pNode.children.get(index);  
  55.                     if(!pChildNode.isSelected())  
  56.                         break;  
  57.                 }  
  58.                 /*   
  59.                  * 表明pNode所有子結(jié)點(diǎn)都已經(jīng)選中,則選中父結(jié)點(diǎn),  
  60.                  * 該方法是一個遞歸方法,因此在此不需要進(jìn)行迭代,因為  
  61.                  * 當(dāng)選中父結(jié)點(diǎn)后,父結(jié)點(diǎn)本身會向上檢查的。  
  62.                  */ 
  63.                 if(index == pNode.children.size())  
  64.                 {  
  65.                     if(pNode.isSelected() != _isSelected)  
  66.                         pNode.setSelected(_isSelected);  
  67.                 }  
  68.             }  
  69.         }  
  70.         else   
  71.         {  
  72.             /*  
  73.              * 如果是取消父結(jié)點(diǎn)導(dǎo)致子結(jié)點(diǎn)取消,那么此時所有的子結(jié)點(diǎn)都應(yīng)該是選擇上的;  
  74.              * 否則就是子結(jié)點(diǎn)取消導(dǎo)致父結(jié)點(diǎn)取消,然后父結(jié)點(diǎn)取消導(dǎo)致需要取消子結(jié)點(diǎn),但  
  75.              * 是這時候是不需要取消子結(jié)點(diǎn)的。  
  76.              */ 
  77.             if(children != null)  
  78.             {  
  79.                 int index = 0;  
  80.                 for(; index < children.size(); ++ index)  
  81.                 {  
  82.                     CheckBoxTreeNode childNode = (CheckBoxTreeNode)children.get(index);  
  83.                     if(!childNode.isSelected())  
  84.                         break;  
  85.                 }  
  86.                 // 從上向下取消的時候  
  87.                 if(index == children.size())  
  88.                 {  
  89.                     for(int i = 0; i < children.size(); ++ i)  
  90.                     {  
  91.                         CheckBoxTreeNode node = (CheckBoxTreeNode)children.get(i);  
  92.                         if(node.isSelected() != _isSelected)  
  93.                             node.setSelected(_isSelected);  
  94.                     }  
  95.                 }  
  96.             }  
  97.               
  98.             // 向上取消,只要存在一個子節(jié)點(diǎn)不是選上的,那么父節(jié)點(diǎn)就不應(yīng)該被選上。  
  99.             CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;  
  100.             if(pNode != null && pNode.isSelected() != _isSelected)  
  101.                 pNode.setSelected(_isSelected);  
  102.         }  
  103.     }  

 第一個差異通過繼承DefaultMutableTreeNode定義CheckBoxTreeNode解決了,接下來需要解決第二個差異。第二個差異是外觀上的差異,JTree的每個結(jié)點(diǎn)是通過TreeCellRenderer進(jìn)行顯示的。為了解決第二個差異,我們定義一個新的類CheckBoxTreeCellRenderer,該類實現(xiàn)了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 CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer  
  15. {  
  16.     protected JCheckBox check;  
  17.     protected CheckBoxTreeLabel label;  
  18.       
  19.     public CheckBoxTreeCellRenderer()  
  20.     {  
  21.         setLayout(null);  
  22.         add(check = new JCheckBox());  
  23.         add(label = new CheckBoxTreeLabel());  
  24.         check.setBackground(UIManager.getColor("Tree.textBackground"));  
  25.         label.setForeground(UIManager.getColor("Tree.textForeground"));  
  26.     }  
  27.       
  28.     /**  
  29.      * 返回的是一個<code>JPanel</code>對象,該對象中包含一個<code>JCheckBox</code>對象  
  30.      * 和一個<code>JLabel</code>對象。并且根據(jù)每個結(jié)點(diǎn)是否被選中來決定<code>JCheckBox</code>  
  31.      * 是否被選中。  
  32.      */ 
  33.     @Override 
  34.     public Component getTreeCellRendererComponent(JTree tree, Object value,  
  35.             boolean selected, boolean expanded, boolean leaf, int row,  
  36.             boolean hasFocus)  
  37.     {  
  38.         String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);  
  39.         setEnabled(tree.isEnabled());  
  40.         check.setSelected(((CheckBoxTreeNode)value).isSelected());  
  41.         label.setFont(tree.getFont());  
  42.         label.setText(stringValue);  
  43.         label.setSelected(selected);  
  44.         label.setFocus(hasFocus);  
  45.         if(leaf)  
  46.             label.setIcon(UIManager.getIcon("Tree.leafIcon"));  
  47.         else if(expanded)  
  48.             label.setIcon(UIManager.getIcon("Tree.openIcon"));  
  49.         else 
  50.             label.setIcon(UIManager.getIcon("Tree.closedIcon"));  
  51.               
  52.         return this;  
  53.     }  
  54.  
  55.     @Override 
  56.     public Dimension getPreferredSize()  
  57.     {  
  58.         Dimension dCheck = check.getPreferredSize();  
  59.         Dimension dLabel = label.getPreferredSize();  
  60.         return new Dimension(dCheck.width + dLabel.width, dCheck.height < dLabel.height ? dLabel.height: dCheck.height);  
  61.     }  
  62.       
  63.     @Override 
  64.     public void doLayout()  
  65.     {  
  66.         Dimension dCheck = check.getPreferredSize();  
  67.         Dimension dLabel = label.getPreferredSize();  
  68.         int yCheck = 0;  
  69.         int yLabel = 0;  
  70.         if(dCheck.height < dLabel.height)  
  71.             yCheck = (dLabel.height - dCheck.height) / 2;  
  72.         else 
  73.             yLabel = (dCheck.height - dLabel.height) / 2;  
  74.         check.setLocation(0, yCheck);  
  75.         check.setBounds(0, yCheck, dCheck.width, dCheck.height);  
  76.         label.setLocation(dCheck.width, yLabel);  
  77.         label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height);  
  78.     }  
  79.       
  80.     @Override 
  81.     public void setBackground(Color color)  
  82.     {  
  83.         if(color instanceof ColorUIResource)  
  84.             color = null;  
  85.         super.setBackground(color);  
  86.     }  

在CheckBoxTreeCellRenderer的實現(xiàn)中,為了處理背景色等問題,我們重新實現(xiàn)了一個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 CheckBoxTreeLabel extends JLabel  
  13. {  
  14.     private boolean isSelected;  
  15.     private boolean hasFocus;  
  16.       
  17.     public CheckBoxTreeLabel()  
  18.     {  
  19.     }  
  20.       
  21.     @Override 
  22.     public void setBackground(Color color)  
  23.     {  
  24.         if(color instanceof ColorUIResource)  
  25.             color = null;  
  26.         super.setBackground(color);  
  27.     }  
  28.       
  29.     @Override 
  30.     public void paint(Graphics g)  
  31.     {  
  32.         String str;  
  33.         if((str = getText()) != null)  
  34.         {  
  35.             if(0 < str.length())  
  36.             {  
  37.                 if(isSelected)  
  38.                     g.setColor(UIManager.getColor("Tree.selectionBackground"));  
  39.                 else 
  40.                     g.setColor(UIManager.getColor("Tree.textBackground"));  
  41.                 Dimension d = getPreferredSize();  
  42.                 int imageOffset = 0;  
  43.                 Icon currentIcon = getIcon();  
  44.                 if(currentIcon != null)  
  45.                     imageOffset = currentIcon.getIconWidth() + Math.max(0, getIconTextGap() - 1);  
  46.                 g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height);  
  47.                 if(hasFocus)  
  48.                 {  
  49.                     g.setColor(UIManager.getColor("Tree.selectionBorderColor"));  
  50.                     g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, d.height - 1);  
  51.                 }  
  52.             }  
  53.         }  
  54.         super.paint(g);  
  55.     }  
  56.       
  57.     @Override 
  58.     public Dimension getPreferredSize()  
  59.     {  
  60.         Dimension retDimension = super.getPreferredSize();  
  61.         if(retDimension != null)  
  62.             retDimension = new Dimension(retDimension.width + 3, retDimension.height);  
  63.         return retDimension;  
  64.     }  
  65.       
  66.     public void setSelected(boolean isSelected)  
  67.     {  
  68.         this.isSelected = isSelected;  
  69.     }  
  70.       
  71.     public void setFocus(boolean hasFocus)  
  72.     {  
  73.         this.hasFocus = hasFocus;  
  74.     }  

通過定義CheckBoxTreeNode和CheckBoxTreeCellRenderer。我們解決了CheckBoxTree和JTree的兩個根本差異,但是還有一個細(xì)節(jié)問題需要解決,就是CheckBoxTree可以響應(yīng)用戶事件決定是否選中某個結(jié)點(diǎn)。為此,我們?yōu)镃heckBoxTree添加一個響應(yīng)用戶鼠標(biāo)事件的監(jiān)聽器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 CheckBoxTreeNodeSelectionListener extends MouseAdapter  
  11. {  
  12.     @Override 
  13.     public void mouseClicked(MouseEvent event)  
  14.     {  
  15.         JTree tree = (JTree)event.getSource();  
  16.         int x = event.getX();  
  17.         int y = event.getY();  
  18.         int row = tree.getRowForLocation(x, y);  
  19.         TreePath path = tree.getPathForRow(row);  
  20.         if(path != null)  
  21.         {  
  22.             CheckBoxTreeNode node = (CheckBoxTreeNode)path.getLastPathComponent();  
  23.             if(node != null)  
  24.             {  
  25.                 boolean isSelected = !node.isSelected();  
  26.                 node.setSelected(isSelected);  
  27.                 ((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node);  
  28.             }  
  29.         }  
  30.     }  

到此為止,CheckBoxTree所需要的所有組件都已經(jīng)完成了,接下來就是如何使用這些組件。下面給出了使用這些組件的源代碼:

  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. {  
  10.     public static void main(String[] args)  
  11.     {  
  12.         JFrame frame = new JFrame("CheckBoxTreeDemo");  
  13.         frame.setBounds(200200400400);  
  14.         JTree tree = new JTree();  
  15.         CheckBoxTreeNode rootNode = new CheckBoxTreeNode("root");  
  16.         CheckBoxTreeNode node1 = new CheckBoxTreeNode("node_1");  
  17.         CheckBoxTreeNode node1_1 = new CheckBoxTreeNode("node_1_1");  
  18.         CheckBoxTreeNode node1_2 = new CheckBoxTreeNode("node_1_2");  
  19.         CheckBoxTreeNode node1_3 = new CheckBoxTreeNode("node_1_3");  
  20.         node1.add(node1_1);  
  21.         node1.add(node1_2);  
  22.         node1.add(node1_3);  
  23.         CheckBoxTreeNode node2 = new CheckBoxTreeNode("node_2");  
  24.         CheckBoxTreeNode node2_1 = new CheckBoxTreeNode("node_2_1");  
  25.         CheckBoxTreeNode node2_2 = new CheckBoxTreeNode("node_2_2");  
  26.         node2.add(node2_1);  
  27.         node2.add(node2_2);  
  28.         rootNode.add(node1);  
  29.         rootNode.add(node2);  
  30.         DefaultTreeModel model = new DefaultTreeModel(rootNode);  
  31.         tree.addMouseListener(new CheckBoxTreeNodeSelectionListener());  
  32.         tree.setModel(model);  
  33.         tree.setCellRenderer(new CheckBoxTreeCellRenderer());  
  34.         JScrollPane scroll = new JScrollPane(tree);  
  35.         scroll.setBounds(00300320);  
  36.         frame.getContentPane().add(scroll);  
  37.           
  38.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  39.         frame.setVisible(true);  
  40.     }  

其執(zhí)行結(jié)果如下圖所示:

原文鏈接:http://blog.csdn.net/wangpingfang/article/details/7174540

【編輯推薦】

  1. Java網(wǎng)絡(luò)編程菜鳥進(jìn)階:TCP和套接字入門
  2. 三個類似Sinatra的Java框架介紹
  3. Java調(diào)用C/C++編寫的第三方dll動態(tài)鏈接庫
  4. 《青花瓷》JAVA版:周杰倫告訴你怎么學(xué)Java
  5. Java網(wǎng)頁數(shù)據(jù)采集器實例教程:數(shù)據(jù)存儲
責(zé)任編輯:林師授 來源: wangpingfang的博客
相關(guān)推薦

2010-01-25 10:35:12

Android復(fù)選框

2009-12-31 17:26:43

Silverlight

2009-11-24 19:12:58

PHP接收復(fù)選框信息

2024-01-12 10:25:51

PyQt6Python復(fù)選框

2016-12-13 10:32:33

EasyUIComboTree任務(wù)

2011-04-11 14:14:29

checkboxlistviewAndroid

2020-11-27 07:54:53

Golang GinW

2021-10-25 09:13:07

前端開發(fā)技術(shù)

2009-11-17 11:24:00

PHP應(yīng)用技巧

2022-04-26 10:46:53

微軟Windows 11

2015-07-07 10:20:47

WebCSS框架

2010-08-06 15:11:44

Flex界面控件

2009-07-16 12:58:50

Swing控件

2020-12-03 09:28:05

Golang GinW

2020-12-02 11:18:28

Golang GinW

2012-03-29 15:15:49

Java

2018-07-04 09:59:23

Android評論回復(fù)

2020-11-24 08:45:04

Active Choi

2023-09-27 09:39:08

Java優(yōu)化

2012-03-08 11:23:09

jQuery Mobi
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號