2015-09-28 65 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()處理僅處理一次..