关于 java:Custom JTree cell renderers with custom open/close icons

Custom JTree cell renderers with custom open/close icons

我想创建一个自定义的 JTree,它的节点是 JProgressBar\\'s 我有这个工作就像我想要的那样

enter

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.testingarea;

import java.awt.Component;
import java.awt.Graphics;
import java.util.HashMap;

import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.plaf.IconUIResource;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;

public class TestTrees {  

  public static void main(String args[]) {  
    JFrame frame = new JFrame("Tree");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    ProgressTreeCellRenderer renderer = new ProgressTreeCellRenderer();

    JProgressBar progressBar = new JProgressBar(0, 100);
    progressBar.setValue(50);
    progressBar.setStringPainted(true);
    DefaultMutableTreeNode top =
        new DefaultMutableTreeNode(progressBar);
    renderer.getNodeMap().put(top, new ProgressTreeCellRenderer2(progressBar));

    createNodes(top, renderer);
    DefaultTreeModel model = new DefaultTreeModel(top);    

    JTree tree = new JTree(model);
    tree.setCellRenderer(renderer);
    JScrollPane pane = new JScrollPane(tree);
    tree.clearSelection();
    frame.getContentPane().add(pane);  
    frame.setSize(250, 250);  
    frame.setVisible(true);  
  }

  private static void createNodes(DefaultMutableTreeNode top, ProgressTreeCellRenderer renderer) {
    JProgressBar progressBar1 = new JProgressBar(0, 100);
    progressBar1.setValue(25);
    progressBar1.setStringPainted(true);
    DefaultMutableTreeNode one =
        new DefaultMutableTreeNode(progressBar1);
    top.add(one);
    renderer.getNodeMap().put(one, new ProgressTreeCellRenderer2(progressBar1));

    JProgressBar progressBar2 = new JProgressBar(0, 100);
    progressBar2.setValue(25);
    progressBar2.setStringPainted(true);
    DefaultMutableTreeNode two =
        new DefaultMutableTreeNode(progressBar2);
    top.add(two);
    renderer.getNodeMap().put(two, new ProgressTreeCellRenderer2(progressBar2));
  }

}

@SuppressWarnings("serial")
class ProgressTreeCellRenderer extends DefaultTreeCellRenderer {

  private HashMap<DefaultMutableTreeNode, ProgressTreeCellRenderer2> nodeMap = new HashMap<DefaultMutableTreeNode, ProgressTreeCellRenderer2>();

  @Override
  public Component getTreeCellRendererComponent(JTree tree, final Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
    if(nodeMap.containsKey(value)) {
      //I was expecting this to work, alas it does not?
      setClosedIcon(new IconUIResource(new NodeIcon('+')));
      setOpenIcon(new IconUIResource(new NodeIcon('-')));
      return nodeMap.get(value).getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
    }
    return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
  }

  public HashMap<DefaultMutableTreeNode, ProgressTreeCellRenderer2> getNodeMap() {
    return nodeMap;
  }
}

class ProgressTreeCellRenderer2 implements TreeCellRenderer {

  private JProgressBar _progressBar;
  private DefaultTreeCellRenderer _defaultRenderer;

  public ProgressTreeCellRenderer2(JProgressBar progressBar) {
    _progressBar = progressBar;
    _defaultRenderer = new DefaultTreeCellRenderer();
  }

  @Override
  public Component getTreeCellRendererComponent(JTree tree, final Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
    Component render = _defaultRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
    final JPanel panel = new JPanel();
    BoxLayout layout = new BoxLayout(panel, BoxLayout.X_AXIS);

    panel.setLayout(layout);
    panel.add(_progressBar);
    render = panel;    
    return render;
  }

}

class NodeIcon implements Icon {

  private static final int SIZE = 9;

  private char type;

  public NodeIcon(char type) {
    this.type = type;
  }

  public void paintIcon(Component c, Graphics g, int x, int y) {
    g.setColor(UIManager.getColor("Tree.background"));
    g.fillRect(x, y, SIZE - 1, SIZE - 1);

    g.setColor(UIManager.getColor("Tree.hash").darker());
    g.drawRect(x, y, SIZE - 1, SIZE - 1);

    g.setColor(UIManager.getColor("Tree.foreground"));
    g.drawLine(x + 2, y + SIZE / 2, x + SIZE - 3, y + SIZE / 2);
    if (type == '+') {
      g.drawLine(x + SIZE / 2, y + 2, x + SIZE / 2, y + SIZE - 3);
    }
  }

  public int getIconWidth() {
    return SIZE;
  }

  public int getIconHeight() {
    return SIZE;
  }
}

如果 ProgressTreeCellRenderer 调用 setClosedIconsetOpenIcon 无效,因为您正在返回从 nodeMap 检索的另一个渲染器。您必须在 ProgressTreeCellRenderer2 的实现中添加图标。例如,尝试这样在 ProgressTreeCellRenderer2 的面板中添加一个图标:

1
panel.add((new JLabel((Icon)UIManager.get("Tree.closedIcon"))));

但是,请注意,您当前的实现非常昂贵。不仅每个节点都有一个新的渲染器,而且您在 getTreeCellRendererComponent() 内重新分配面板实例。尝试对具有预分配控件的所有节点使用单个渲染器,在这些节点中,您仅根据 getTreeCellRendererComponent 的参数更新属性。有关渲染器详细信息和树显示自定义示例,请参阅如何使用树。

看看这个答案(由@mKorbel 提供),它说明了表格中的单个进度条渲染器。