I have a Swing based logger that comes packaged with my application, the logger should display line numbers next to each line of the log output..
The log output is displayed within a JTextArea
, within a JScrollPane
.
I am using setRowHeaderView()
with a custom view to display the line numbers.
The issue that I am having, is that within the custom iew to display line numbers, the paintComponent()
method seems to be called twice for each update, the second time having incorrect clipBounds.
Creating the TextArea:
public static void main(String[] args) {
JFrame frame = new JFrame();
JScrollPane scroll = new JScrollPane(new JTextArea(50, 150));
scroll.setRowHeaderView(new MyHeaderView());
frame.add(scroll);
frame.pack();
frame.setVisible(true);
}
Then
public class MyHeaderView extends JPanel {
private final int pxPerLine;
public MyHeaderView() {
super();
this.setPreferredSize(new Dimension(50, 10));
FontMetrics fm = getFontMetrics(getFont());
this.pxPerLine = (int) (fm.getHeight() / 2.0f) + 2;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle clip = g.getClipBounds();
System.out.println(clip.toString());
g.setColor(Color.BLACK);
g.fillRect(clip.x, clip.y, clip.width, clip.height);
int pxStart = clip.y;
int stStart = pxStart / pxPerLine;
int stCount = clip.height / pxPerLine;
g.setColor(Color.YELLOW);
for (int x = 0; x < stCount; x++) {
String t = "" + (stStart + x);
g.drawString(t, 5, pxStart + (pxPerLine * x));
}
}
}
What this result in, is something that looks like this, no matter where I scroll to:
However, if I use the debugger and step through the paintComponent
method, I can see that each time the numbers should draw, the method is called twice. The first time through, g.getClipBounds()
returns the correct values:
However, the second time, the clip bound are always back to the origin bounds, causing just the first few line numbers to be drawn.
Question
Why is the final time through the paintComponent
method called with incorrect clip bounds, when the text area itself is in the correct position?
After adding a bunch of new lines to the above code and scrolling around the UI:
java.awt.Rectangle[x=0,y=497,width=50,height=16]
java.awt.Rectangle[x=0,y=0,width=50,height=16]
java.awt.Rectangle[x=0,y=481,width=50,height=16]
java.awt.Rectangle[x=0,y=0,width=50,height=16]
java.awt.Rectangle[x=0,y=465,width=50,height=16]
java.awt.Rectangle[x=0,y=0,width=50,height=16]
java.awt.Rectangle[x=0,y=446,width=50,height=16]
java.awt.Rectangle[x=0,y=0,width=50,height=16]
Note that the the update jump from valid to origin and back again, and the seconds update always seems to reset me back to the origin..
Why is the being updated twice?