我的应用程序随附了一个基于Swing的记录器,记录器应在日志输出的每一行旁边显示行号。
日志输出显示在JTextArea
和JScrollPane
中。
我在自定义视图中使用setRowHeaderView()
来显示行号。
我遇到的问题是,在用于显示行号的自定义iew中,paintComponent()
方法似乎每次更新都被调用两次,第二次有不正确的clipBounds。
创建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);
}
然后
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));
}
}
}
无论我滚动到什么地方,结果都是这样的:
但是,如果我使用调试器并逐步完成paintComponent
方法,则可以看到每次绘制数字时,该方法都会被调用两次。第一次g.getClipBounds()
返回正确的值:
但是,第二次,剪辑边界始终返回到原点边界,从而仅绘制了前几行。
问题
当文本区域本身处于正确位置时,为什么通过paintComponent
方法的最终时间以不正确的剪辑范围调用?
在上述代码中添加了一堆新行并在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]
请注意,更新从有效跳到原点,然后又返回原点,而秒更新总是使我重回原点。
为什么要两次更新?