2015-09-28 40 views
1
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); 
    } 
} 

在上面的代码(完整的代码可以在“执行风俗画” Java教程的Demo App找到),第一repaint方法应该画一个正方形的前一个广场的位置,第二个repaint应在新广场的位置绘制另一个广场。但这实际上并没有发生。相反,前面的方块消失了,新的方块也被涂上了。风俗画重绘

新方形在前一个消失时如何绘制?

+0

请正确缩进此。否则,我无法真正阅读它。 –

+1

'repaint'不会立即发生,它们被发布到事件队列中并在将来的某个时刻处理,因为'moveSquare'方法在EDT中执行,您可以保证重绘不会直到'moveSquare'方法退出之后才会发生 – MadProgrammer

回答

0

Oracle docs给出了很好的解释: moveSquare方法调用repaint方法不是一次,而是两次。第一次调用告诉Swing重新绘制前一个方块所在组件的区域(继承的行为使用UI委托用当前背景颜色填充该区域)。第二次调用绘制了当前正方形所在组件的区域。

+0

是的,我读过那个,但是这行“继承的行为使用UI委托来用当前背景颜色填充该区域。”它说它用背景颜色(白色)绘制它,但fillRect方法应该用当前设置的颜色绘制它。为什么? –

+0

调试你的代码,你会明白在'repaint'方法中发生了什么 – Vaseph

+0

*“继承的行为使用UI委托来用当前背景颜色填充该区域。” - 但是'paint'方法将方块的颜色设置为被绘,所以这个陈述实际上是不真实的。其他两个答案其实是正确的 – MadProgrammer

1

您链接到回答你的问题的文档,至少在一般:

虽然我们在同一个事件处理连续调用repaint两次,Swing是足够聪明,采取信息和重绘那些屏幕的所有部分都在一次涂装操作中。

当你调用repaint,你实际上并没有画任何东西,但在未来请求重绘在一段时间。

虽然repaint JavaDoc不进入任何细节,它包括一个链接到“Painting in AWT and Swing”,其中包括在“Paint Processing”部分两种情况下,其中的第二适用于这里:

(B )[当]涂料请求从上的javax.swing.JComponent一个扩展repaint()一个呼叫始发:

JComponent.repaint()寄存器的异步的重画请求到组件的RepaintManager,它使用invokeLater()排队一个Runnable稍后在事件派发线程上处理请求。

在那部分后:

注意:如果到repaint()多个呼叫的部件或任何其摇摆祖先上发生被处理重绘请求之前,那些多个请求可以被折叠成单呼回paintImmediately() [...]

到时候你的事件处理程序返回时,JPanel的某些部分(S)将被标记为重新粉刷,可能这一切。这些被称为“脏区”。 Swing(最终)一次重绘所有脏区域,并且只能重绘一次。在之后,您的活动处理程序已返回 - 这意味着在JPanel的外观已更改之后发生此绘画---所以彩色方块出现在其新位置,其旧位置没有任何“剩菜”。

总之,不要以为repaint为“重画这个区域现在”,而是“将此区域添加到您的油漆列表中 - 稍后 - 某一时间”。

1

在您致电repaint()之后,它不会立即重新绘制组件。但它添加了在EDT中的事件队列中再次绘制组件的请求。

在每行代码会发生什么情况如下expained ..

repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); 

马克由方(squareX,squareY,squareW+OFFSET,squareH+OFFSET)围成的区域将是重新绘制。但它没有得到重新绘制,直到RepaintManager这样做..

squareX=x; 
squareY=y; 

变化squareXsquareY值。但它不会改变早先标记的区域进行重新粉刷。现在,要重新绘制的区域也是先前的值。

repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); 

标记由方块(squareX,squareY,squareW+OFFSET,squareH+OFFSET)包围的区域将被重新绘制。现在有两个部分RepaintManager必须重新绘制。上一个广场和新广场。但它不会被重新粉刷,直到RepaintManager这样做。

最后当时间到了,RepaintManager绘制组件。

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

现在组件只绘制2个区域。 (以前的广场和新的广场)但是红色的广场只会在新的广场内画出。在老广场上没有什么可以画的。所以先前绘制的东西将被删除..

其实虽然有2个方法调用repaint()paintComponents()将只被调用一次。要重新绘制的总面积由RepaintManagerpaintComponents()处理仅处理一次..