成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java中帶復選框的樹的實現和應用

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

在使用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 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.             // 如果選中,則將其所有的子結點都選中  
  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.             // 向上檢查,如果父結點的所有子結點都被選中,那么將父結點也選中  
  47.             CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;  
  48.             // 開始檢查pNode的所有子節點是否都被選中  
  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所有子結點都已經選中,則選中父結點,  
  60.                  * 該方法是一個遞歸方法,因此在此不需要進行迭代,因為  
  61.                  * 當選中父結點后,父結點本身會向上檢查的。  
  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.              * 如果是取消父結點導致子結點取消,那么此時所有的子結點都應該是選擇上的;  
  74.              * 否則就是子結點取消導致父結點取消,然后父結點取消導致需要取消子結點,但  
  75.              * 是這時候是不需要取消子結點的。  
  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.             // 向上取消,只要存在一個子節點不是選上的,那么父節點就不應該被選上。  
  99.             CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;  
  100.             if(pNode != null && pNode.isSelected() != _isSelected)  
  101.                 pNode.setSelected(_isSelected);  
  102.         }  
  103.     }  

 第一個差異通過繼承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 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>對象。并且根據每個結點是否被選中來決定<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的實現中,為了處理背景色等問題,我們重新實現了一個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的兩個根本差異,但是還有一個細節問題需要解決,就是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 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所需要的所有組件都已經完成了,接下來就是如何使用這些組件。下面給出了使用這些組件的源代碼:

  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.     }  

其執行結果如下圖所示:

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

【編輯推薦】

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

2010-01-25 10:35:12

Android復選框

2009-12-31 17:26:43

Silverlight

2009-11-24 19:12:58

PHP接收復選框信息

2024-01-12 10:25:51

PyQt6Python復選框

2016-12-13 10:32:33

EasyUIComboTree任務

2011-04-11 14:14:29

checkboxlistviewAndroid

2021-10-25 09:13:07

前端開發技術

2020-11-27 07:54:53

Golang GinW

2009-11-17 11:24:00

PHP應用技巧

2015-07-07 10:20:47

WebCSS框架

2010-08-06 15:11:44

Flex界面控件

2022-04-26 10:46:53

微軟Windows 11

2009-07-16 12:58:50

Swing控件

2020-12-03 09:28:05

Golang GinW

2012-03-29 15:15:49

Java

2020-12-02 11:18:28

Golang GinW

2020-11-24 08:45:04

Active Choi

2018-07-04 09:59:23

Android評論回復

2012-03-08 11:23:09

jQuery Mobi

2023-09-27 09:39:08

Java優化
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美黑人一级爽快片淫片高清 | 亚洲成人av在线播放 | 欧美日韩三区 | 国产区在线观看 | 日韩在线观看一区 | 亚洲乱码国产乱码精品精98午夜 | 2019天天干天天操 | 亚洲国产精品一区二区三区 | 国产乱码精品一区二区三区五月婷 | 古装三级在线播放 | 国产成人精品一区二 | 一级特黄色毛片 | 婷婷去俺也去 | 久久久久久久国产精品影院 | 亚洲久在线 | 久久久久久高潮国产精品视 | www狠狠干 | 国产婷婷色综合av蜜臀av | 日本国产高清 | 最近中文字幕第一页 | 一区二区三区在线观看免费视频 | 亚洲视频一区在线播放 | 国产精品成人一区二区 | 亚洲大片在线观看 | 亚洲高清在线 | 四虎影院一区二区 | 日韩电影免费在线观看中文字幕 | 日韩国产三区 | 日韩伦理一区二区 | 亚洲欧美综合 | 开操网 | 亚洲国产精品一区二区第一页 | 日韩精品在线看 | 国产欧美一区二区三区日本久久久 | 伊人狠狠 | 欧美中国少妇xxx性高请视频 | 日韩在线精品视频 | 欧美精品一二三区 | 国产精品久久久久久妇女6080 | 日本不卡视频在线播放 | 免费观看a级毛片在线播放 黄网站免费入口 |