12.10.6 实现TreeCellRenderer改变节点外观

12.10.6 实现TreeCellRenderer改变节点外观

这种方式是最灵活的方式,程序实现TreeCellRenderer接口时同样需要实现getTreeCellRendererComponent()方法,该方法可以返回任意类型的组件,该组件将作为JTree的节点。通过这种方式可以最大程度地改变JTree的节点外观。
与前面实现ListCellRenderer接口类似的是,本实例程序同样通过扩展JPanel来实现TreeCellRenderer,实现TreeCellRenderer的方式与前面实现ListCellRenderer的方式基本相似,所以读者将会看到一个完全不同的JTree

程序 实现TreeCellRenderer改变节点外观

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
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;

public class CustomTreeNode {
JFrame jf = new JFrame("定制树的节点");
JTree tree;
// 定义几个初始节点
DefaultMutableTreeNode friends = new DefaultMutableTreeNode("我的好友");
DefaultMutableTreeNode qingzhao = new DefaultMutableTreeNode("李清照");
DefaultMutableTreeNode suge = new DefaultMutableTreeNode("苏格拉底");
DefaultMutableTreeNode libai = new DefaultMutableTreeNode("李白");
DefaultMutableTreeNode nongyu = new DefaultMutableTreeNode("弄玉");
DefaultMutableTreeNode hutou = new DefaultMutableTreeNode("虎头");

public void init() {
// 通过add()方法建立树节点之间的父子关系
friends.add(qingzhao);
friends.add(suge);
friends.add(libai);
friends.add(nongyu);
friends.add(hutou);
// 以根节点创建树
tree = new JTree(friends);
// 设置是否显示根节点的“展开/折叠”图标,默认是false
tree.setShowsRootHandles(true);
// 设置节点是否可见,默认是true
tree.setRootVisible(true);
// 设置使用定制的节点绘制器
tree.setCellRenderer(new ImageCellRenderer());
jf.add(new JScrollPane(tree));
jf.pack();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
}

public static void main(String[] args) {
new CustomTreeNode().init();
}
}

// 实现自己的节点绘制器
class ImageCellRenderer extends JPanel implements TreeCellRenderer {
private ImageIcon icon;
private String name;
// 定义绘制单元格时的背景色
private Color background;
// 定义绘制单元格时的前景色
private Color foreground;

public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf,
int row, boolean hasFocus) {
icon = new ImageIcon("icon/" + value + ".gif");
name = value.toString();
background = hasFocus ? new Color(140, 200, 235) : new Color(255, 255, 255);
foreground = hasFocus ? new Color(255, 255, 3) : new Color(0, 0, 0);
// 返回该JPanel对象作为单元格绘制器
return this;
}

// 重写paintComponent方法,改变JPanel的外观
public void paintComponent(Graphics g) {
int imageWidth = icon.getImage().getWidth(null);
int imageHeight = icon.getImage().getHeight(null);
g.setColor(background);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(foreground);
// 绘制好友图标
g.drawImage(icon.getImage(), getWidth() / 2 - imageWidth / 2, 10, null);
g.setFont(new Font("SansSerif", Font.BOLD, 18));
// 绘制好友用户名
g.drawString(name, getWidth() / 2 - name.length() * 10, imageHeight + 30);
}

// 通过该方法来设置该ImageCellRenderer的最佳大小
public Dimension getPreferredSize() {
return new Dimension(80, 80);
}
}

上面程序中的粗体字代码设置JTree对象使用定制的节点绘制器:ImageCellRenderer,该节点绘制器实现了TreeCellRenderer接口的getTreeCellRendererComponent()方法,该方法返回thi,也就是一个特殊的JPanel对象,这个特殊的JPanel重写了paintComponent()方法,重新绘制了JPanel的外观—根据节点数据来绘制图标和文本。运行上面程序,会看到如图12.46所示的树。


这看上去似乎不太像一棵树,但可从每个节点前的连接线、表示节点的展开/折叠的图标中看出这依然是一棵树。