Code
class TableOfContentsTree extends JTree {
private static final BasicStroke READER = new BasicStroke(
1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f, new float[] { 1f }, 0f);
private boolean isSynth = false;
public TableOfContentsTree(TreeModel model) {
super(model);
}
@Override public void updateUI() {
super.updateUI();
setBorder(BorderFactory.createTitledBorder("JTree#paintComponent(...)"));
isSynth = getUI().getClass().getName().contains("Synth");
}
private Rectangle getVisibleRowsRect() {
Insets i = getInsets();
Rectangle visRect = getVisibleRect();
if(visRect.x == 0 && visRect.y == 0 && visRect.width == 0 &&
visRect.height == 0 && getVisibleRowCount() > 0) {
// The tree doesn't have a valid bounds yet. Calculate
// based on visible row count.
visRect.width = 1;
visRect.height = getRowHeight() * getVisibleRowCount();
}else{
visRect.x -= i.left;
visRect.y -= i.top;
}
// we should consider a non-visible area above
Component component = SwingUtilities.getUnwrappedParent(this);
if(component instanceof JViewport) {
component = component.getParent();
if(component instanceof JScrollPane) {
JScrollPane pane = (JScrollPane) component;
JScrollBar bar = pane.getHorizontalScrollBar();
if(bar != null && bar.isVisible()) {
int height = bar.getHeight();
visRect.y -= height;
visRect.height += height;
}
}
}
return visRect;
}
@Override public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
FontMetrics fm = g.getFontMetrics();
int pnmaxWidth = fm.stringWidth("000");
Insets ins = getInsets();
Rectangle rect = getVisibleRowsRect();
for(int i=0;i< getRowCount();i++) {
Rectangle r = getRowBounds(i);
if(rect.intersects(r)) {
TreePath path = getPathForRow(i);
TreeCellRenderer tcr = getCellRenderer();
JComponent c = (JComponent)tcr;
if(isSynth && isRowSelected(i)) {
if(tcr instanceof DefaultTreeCellRenderer) {
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer)tcr;
g2.setColor(renderer.getTextSelectionColor());
}
}else{
g2.setColor(getForeground());
}
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
Object o = node.getUserObject();
if(o instanceof TableOfContents) {
TableOfContents toc = (TableOfContents)o;
String pn = "" + toc.page;
int x = getWidth() -1 - fm.stringWidth(pn) - ins.right;
//int y = (int)(0.5 + r.y + (r.height + fm.getAscent()) * 0.5);
int y = r.y + c.getBaseline(r.width, r.height);
g2.drawString(pn, x, y);
int gap = 5;
int x2 = getWidth() -1 - pnmaxWidth - ins.right;
Stroke s = g2.getStroke();
g2.setStroke(READER);
g2.drawLine(r.x + r.width + gap, y, x2 - gap, y);
g2.setStroke(s);
}
}
}
g2.dispose();
}
}
References