在重画过程中调用paintComponent()时

时间:2018-07-11 13:52:15

标签: java swing

根据我上一篇有关绘画的建议,我正在遵循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进入哪里了?当我们说重画时会调用它吗?如果是这样,为什么它也不会在以前的位置绘制一个矩形?

1 个答案:

答案 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,建议需要绘制的组件区域。

  1. 第一个repaint()建议要绘制的区域。
  2. 第二个repaint()建议另一个要绘制的区域。

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();

您仍将具有相同的绘画结果(使用更简单的代码)。只需注意,无论单击何处,剪辑边界现在都等于整个面板的大小。