Folks,
I am trying to create a gradient JTree control. The following code mostly works except that the background for the tree cell is not transparent. I would appreciate it if someone call tell me what is it that I am not doing right.
Thank you in advance for your help.
Regards,
Peter
package TestPackage;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
public class Test {
public Test() {
JFrame frame = new JFrame();
JPanel framePanel = new JPanel();
framePanel.setLayout(new BorderLayout());
frame.setContentPane(framePanel);
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Item");
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode("Child");
rootNode.add(childNode);
GradientTree tree = new GradientTree(rootNode);
// JTree tree = new JTree(rootNode);
// tree.setBackground(Color.blue);
tree.setCellRenderer(new MyRenderer());
JScrollPane scroll = new JScrollPane(tree);
scroll.setOpaque(false);
framePanel.add(scroll, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Test();
}
});
}
@SuppressWarnings("serial")
public static class GradientTree extends JTree {
public GradientTree(DefaultMutableTreeNode node) {
super(node);
}
@Override
protected void paintComponent(Graphics g) {
int h = getHeight();
int w = getWidth();
GradientPaint gradientPaint = new GradientPaint(0, 0, Color.LIGHT_GRAY, 0, h, Color.WHITE);
Graphics2D g2D = (Graphics2D) g;
g2D.setPaint(gradientPaint);
g2D.fillRect(0, 0, w, h);
this.setOpaque(false);
super.paintComponent(g);
this.setOpaque(true);
}
}
@SuppressWarnings({"serial" })
private class MyRenderer extends DefaultTreeCellRenderer {
public MyRenderer() {
this.setOpaque(false);
this.setForeground(Color.RED);
}
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(
tree, value, sel,
expanded, leaf, row,
hasFocus);
return this;
}
}
}
This is a real pain. The DefaultTreeCellRenderer
will ignore the opaque
value and fill it's contents anyway. However, there is a flag you can try. I've done it in the past, but don't have time to test it...
Try UIManager.put("Tree.rendererFillBackground", false)
. Try and do this before anything is renderer, but after any look and feel settings have been applied.
UPDATED
It is very important to set this property BEFORE you create any trees
Without | With...
public class TestTreeRenderer {
public static void main(String[] args) {
new TestTreeRenderer();
}
public TestTreeRenderer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TreePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TreePane extends JPanel {
private JTree tree;
public TreePane() {
// THIS IS VERY IMPORTANT
// You must set this BEFORE creating ANY trees!!
UIManager.put("Tree.rendererFillBackground", false);
setLayout(new BorderLayout());
tree = new JTree();
tree.setBackground(Color.BLUE);
System.out.println("Loading files...");
File root = new File("/etc");
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(root.getName());
for (File file : root.listFiles()) {
rootNode.add(new DefaultMutableTreeNode(file.getName()));
}
System.out.println("Loading model");
DefaultTreeModel model = new DefaultTreeModel(rootNode);
tree.setModel(model);
add(new JScrollPane(tree));
}
}
}