一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務(wù)器之家 - 編程語言 - JAVA教程 - Java帶復(fù)選框的樹(Java CheckBox Tree)實(shí)現(xiàn)和應(yīng)用

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

2021-02-19 23:10女武神的騎行 JAVA教程

這篇文章主要為大家詳細(xì)介紹了Java帶復(fù)選框的樹實(shí)現(xiàn)和應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

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

CheckBoxTree與JTree在兩個(gè)層面上存在差異:

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

既然存在兩個(gè)差異,那么只要我們把這兩個(gè)差異部分通過自己的實(shí)現(xiàn)填補(bǔ)上,那么帶復(fù)選框的樹也就實(shí)現(xiàn)了。
現(xiàn)在開始解決第一個(gè)差異。為了解決第一個(gè)差異,需要定義一個(gè)新的結(jié)點(diǎn)類CheckBoxTreeNode,該類繼承DefaultMutableTreeNode,并增加新的成員isSelected來表示該結(jié)點(diǎn)是否被選中。對于一顆CheckBoxTree,如果某一個(gè)結(jié)點(diǎn)被選中的話,其復(fù)選框會(huì)勾選上,并且使用CheckBoxTree的動(dòng)機(jī)在于可以一次性地選中一顆子樹。那么,在選中或取消一個(gè)結(jié)點(diǎn)時(shí),其祖先結(jié)點(diǎn)和子孫結(jié)點(diǎn)應(yīng)該做出某種變化。在此,我們應(yīng)用如下遞歸規(guī)則:

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

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

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

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

第一個(gè)差異通過繼承DefaultMutableTreeNode定義CheckBoxTreeNode解決了,接下來需要解決第二個(gè)差異。第二個(gè)差異是外觀上的差異,JTree的每個(gè)結(jié)點(diǎn)是通過TreeCellRenderer進(jìn)行顯示的。為了解決第二個(gè)差異,我們定義一個(gè)新的類CheckBoxTreeCellRenderer,該類實(shí)現(xiàn)了TreeCellRenderer接口。CheckBoxTreeRenderer的源代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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"));
 }
  
 /**
  * 返回的是一個(gè)<code>JPanel</code>對象,該對象中包含一個(gè)<code>JCheckBox</code>對象
  * 和一個(gè)<code>JLabel</code>對象。并且根據(jù)每個(gè)結(jié)點(diǎn)是否被選中來決定<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的實(shí)現(xiàn)中,getTreeCellRendererComponent方法返回的是JPanel,而不是像DefaultTreeCellRenderer那樣返回JLabel,因此JPanel中的JLabel無法對選中做出反應(yīng),因此我們重新實(shí)現(xiàn)了一個(gè)JLabel的子類CheckBoxTreeLabel,它可以對選中做出反應(yīng),其源代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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的兩個(gè)根本差異,但是還有一個(gè)細(xì)節(jié)問題需要解決,就是CheckBoxTree可以響應(yīng)用戶事件決定是否選中某個(gè)結(jié)點(diǎn)。為此,我們?yōu)镃heckBoxTree添加一個(gè)響應(yīng)用戶鼠標(biāo)事件的監(jiān)聽器CheckBoxTreeNodeSelectionListener,該類的源代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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所需要的所有組件都已經(jīng)完成了,接下來就是如何使用這些組件。下面給出了使用這些組件的源代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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);
 }
}

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

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 麻豆最新地址 | 久青草国产97香蕉在线视频 | 国产真实一区二区三区 | 99爱在线精品视频免费观看9 | 亚洲欧美国产在线 | 91精品国产高清久久久久久io | les在宿舍吃她奶 | 国产精品免费精品自在线观看 | 成人高辣h视频一区二区在线观看 | 精品九九视频 | 久久不射电影网 | 精品在线免费观看 | 日日爽 | 午夜在线a亚洲v天堂网2019 | 无遮掩60分钟从头啪到尾 | 欧美高清videosdesex0 | 成年男人永久免费看片 | 黑人巨摘花第一次出血 | 国内精品久久久久久不卡影院 | 四虎影院在线免费观看 | 四虎永久在线精品免费影视 | 日本红色高清免费观看 | 黄色大片网| 草莓视频在线观看免费 | 日本五十路六十30人8时间 | 天天射夜夜爽 | 免费观看欧美成人禁片 | 国产真实乱子伦xxxxchina | 黑人开嫩苞 | 色哟哟哟在线精品观看视频 | 亚洲国产精品久久精品成人网站 | 精品国产影院 | 日韩一区在线播放 | 成年视频在线观看免费 | 午夜宅男在线观看 | 九九九九九九精品免费 | 精品国产美女AV久久久久 | 农夫色综合 | 国产青青草 | 特黄特色大片免费影院 | 91短视频社区在线观看 |