根据我上一篇有关绘画的建议,我正在遵循Oracle Swing教程。现在,我对何时以及如何调用paintComponent()方法感到困惑。
这是课程:
public class MyPanel extends JPanel
{
private int squareX=50;
private int squareY=50;
private int squareW=50;
private int squareH=20;
public MyPanel()
{
setBorder(BorderFactory.createLineBorder(Color.BLACK));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquare(e.getX(), e.getY());
}
});
addMouseMotionListener(new MouseAdapter(){
public void mouseDragged(MouseEvent e) {
moveSquare(e.getX(), e.getY());
}
});
}
private void moveSquare(int x, int y)
{
int OFFSET = 1;
if((squareX!=x)||(squareY!=y))
{
repaint(squareX, squareY, squareW+OFFSET, squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX, squareY, squareW+OFFSET, squareH+OFFSET);
}
}
public Dimension getPreferredSize()
{
return new Dimension(250, 200);
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString("This is my custom panel!", 10, 20);
g.setColor(Color.RED);
g.fillRect(squareX, squareY, squareW, squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX, squareY, squareW, squareH);
}
}
本教程说,这两种重绘方法都将重绘以前的鼠标位置以及新的鼠标位置。我明白了,但是paintComponent进入哪里了?当我们说重画时会调用它吗?如果是这样,为什么它也不会在以前的位置绘制一个矩形?
答案 0 :(得分:0)
repaint()方法将绘制请求传递到RepaintManager
。
在短时间内收到多个请求时,RepaintManager
会将两个单独的请求合并为一个请求,以提高绘画效率。
所以,如果您有类似的东西:
repaint(5, 5, 20, 20);
...
repaint( 30, 30, 20, 20);
RepaintManager
最终将它们合并为(5, 5, 45, 45)
的单个重绘。这个较大的区域将包括两个单独请求的区域。
然后RepaintManager
将在组件上调用paint()
,该组件依次使用裁剪区域来调用paintComponent(...)
方法。然后,paintCompnent()
方法将绘制剪切区域的背景(这将从背景中清除旧的正方形),然后在其新位置绘制正方形。
编辑:
repaint()
方法不做任何绘画。 The repaint()
方法仅调用RepaintManager
,建议需要绘制的组件区域。
RepaintManager
将两个较小的区域合并为一个较大的区域。几毫秒后,它将告诉组件根据较大的区域对其进行重新绘制(这称为剪辑范围)。每次单击鼠标都会调用paintComponent()
方法。
调用paintComponent(...)
方法时:
super.paintComponent(g);
上面的代码仅绘制受Graphics对象的剪辑范围中指定的区域约束的组件的背景。背景颜色由setBackground(...)方法控制。
g.drawString("This is my custom panel!", 10, 20);
g.setColor(Color.RED);
g.fillRect(squareX, squareY, squareW, squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX, squareY, squareW, squareH);
以上代码将在清除的背景上方绘制正方形。
将绘画代码更改为:
super.paintComponent(g);
System.out.println( g.getClipBounds() );
,您将看到重新绘制的组件的实际区域是两个较小区域的并集。
理论上,较小的区域比较大的区域更有效。但是实际上,在这个简单的示例中没有必要。
按如下所示更改代码:
//repaint(squareX, squareY, squareW+OFFSET, squareH+OFFSET);
squareX=x;
squareY=y;
//repaint(squareX, squareY, squareW+OFFSET, squareH+OFFSET);
repaint();
您仍将具有相同的绘画结果(使用更简单的代码)。只需注意,无论单击何处,剪辑边界现在都等于整个面板的大小。