How do you make a tree node in a JTree stretch over the whole row? A TreeCellRenderer will not work since then the background will only appear to the right of the node. The answer is to use a TreeCellRenderer in combination with a TreeUI. Lets show how with an example.
Lets start of with a main class that creates a frame and adds a JTree.
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
public class Main extends JFrame
{
public Main()
{
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode aa = new DefaultMutableTreeNode("Child AA");
DefaultMutableTreeNode ab = new DefaultMutableTreeNode("Child AB");
DefaultMutableTreeNode aba = new DefaultMutableTreeNode("Child ABA");
DefaultMutableTreeNode abb = new DefaultMutableTreeNode("Child ABB");
DefaultMutableTreeNode abba = new DefaultMutableTreeNode("Child ABBA");
root.add(aa);
root.add(ab);
ab.add(aba);
ab.add(abb);
abb.add(abba);
JTree tree = new MyTree(root);
add(tree);
pack();
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new Main();
}
}
Next, lets create a class that extend JTree.
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
public class MyTree extends JTree
{
public MyTree(DefaultMutableTreeNode root)
{
super(root);
setPreferredSize(new Dimension(200, 300));
setRootVisible(false);
setRowHeight(25);
setBackground(Color.BLUE);
setUI(new MyBasicTreeUI());
setCellRenderer(new MyNodeRenderer());
}
}
Then at last, we create the cell renderer and the tree UI.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
public class MyNodeRenderer implements TreeCellRenderer
{
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus)
{
JPanel panel = new JPanel();
if(selected)
{
panel.setBackground(Color.RED);
}
else
{
panel.setBackground(Color.BLUE);
}
panel.setLayout(new BorderLayout());
panel.setPreferredSize(new Dimension(tree.getWidth(), tree.getRowHeight()));
String text = (String)((DefaultMutableTreeNode)value).getUserObject();
panel.add(new JLabel(text));
return panel;
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.TreePath;
public class MyBasicTreeUI extends BasicTreeUI
{
@Override
public Icon getExpandedIcon()
{
return null;
}
@Override
public Icon getCollapsedIcon()
{
return null;
}
@Override
protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom)
{}
@Override
protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, int right)
{}
@Override
protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf)
{
if(tree.isRowSelected(row))
{
g.setColor(Color.RED);
g.fillRect(0, row * tree.getRowHeight(), tree.getWidth(), tree.getRowHeight());
}
super.paintRow(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
}
}
Actually, you don’t need to set the preferred size on the tree cell renderer panel. But doing so like in this case will make the whole panel clickable.