2010-05-07 97 views
1

我有一個項目,當它存在時,它似乎不斷重新繪製,導致CPU隨着它在我的任何窗口中都會尖峯化。它直接從JLabel繼承,與屏幕上的其他JLabel不同,它具有紅色背景和邊框。我不知道爲什麼它會不同,不斷重新繪畫。這個callstack看起來像這樣:爲什麼JLabel不斷重新粉刷?

Thread [AWT-EventQueue-1] (Suspended (breakpoint at line 260 in sItem)) 
    sItem.paint(Graphics) line: 260 
    sItem(JComponent).paintToOffscreen(Graphics, int, int, int, int, int, int) line: 5124 
    RepaintManager$PaintManager.paintDoubleBuffered(JComponent, Image, Graphics, int, int, int, int) line: 1475 
    RepaintManager$PaintManager.paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1406 
    RepaintManager.paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1220 
    sItem(JComponent)._paintImmediately(int, int, int, int) line: 5072 
    sItem(JComponent).paintImmediately(int, int, int, int) line: 4882 
    RepaintManager.paintDirtyRegions(Map<Component,Rectangle>) line: 803  
    RepaintManager.paintDirtyRegions() line: 714  
    RepaintManager.seqPaintDirtyRegions() line: 694 [local variables unavailable] 
    SystemEventQueueUtilities$ComponentWorkRequest.run() line: 128 
    InvocationEvent.dispatch() line: 209  
    summitEventQueue(EventQueue).dispatchEvent(AWTEvent) line: 597 
    summitEventQueue(SummitHackableEventQueue).dispatchEvent(AWTEvent) line: 26 
    summitEventQueue.dispatchEvent(AWTEvent) line: 62 
    EventDispatchThread.pumpOneEventForFilters(int) line: 269 
    EventDispatchThread.pumpEventsForFilter(int, Conditional, EventFilter) line: 184  
    EventDispatchThread.pumpEventsForHierarchy(int, Conditional, Component) line: 174 
    EventDispatchThread.pumpEvents(int, Conditional) line: 169 
    EventDispatchThread.pumpEvents(Conditional) line: 161 
    EventDispatchThread.run() line: 122 [local variables unavailable] 

它基本上只是不斷地擊中一遍又一遍,只要我可以按繼續。這是「獨一無二」的,以該特定標籤的代碼看起來大約是這樣的:

bgColor = OurColors.clrWindowTextAlert; 
textColor = Color.white; 
setBackground(bgColor); 
setOpaque(true); 
setSize(150, getHeight()); 
Border border_warning = BorderFactory.createCompoundBorder(
     BorderFactory.createMatteBorder(1, 1, 1, 1, OurColors.clrXBoxBorder), 
     Global.border_left_margin); 
setBorder(border_warning); 

顯然,它做更多,但特定塊只存在這些標籤所造成的秒殺/連續重繪。

任何想法爲什麼它會繼續重新繪製這個特定的標籤?

回答

4

大量的代碼丟失了,但我會採取一個有教養的猜測。

該類的「唯一」部分可能在負責呈現標籤的代碼的一部分內。如果這是真的,那麼調用所有這些setXXX()方法可能會使對象變髒,這意味着它需要重新繪製,這將再次輸入此代碼塊,然後使用公共接口更新小部件,然後使對象變髒,導致循環重複。

最終這樣的事情會消耗​​所有的空閒週期,導致CPU顯示最大的標籤,這顯然沒有太大的作用。

嘗試在渲染循環之外的位置設置適當的值。大多數這些項目看起來像可以在構造函數中設置。

---確認後,編輯認爲它是setBorder(...)---

可能設置一個新的邊界觸發小部件的邊框的重新計算,作爲一個邊界可能是更大或更小比以前的邊界。這和新的邊界可能包含不同的屏幕顯示(提高,降低等),舊的。

這些項目都不需要在渲染部分設置,但我敢打賭,與其他項目,進行peliminary檢查,看是否新項目equals(...)舊項目。如果是這樣,那麼(作爲優化),髒位不會被設置,並且刷新請求不會被提交給渲染引擎。

有了邊框,這樣的檢查將不得不覆蓋幾個元素,包括一些被編譯的字節碼(實際的繪圖指令)。由於在考慮邊界時不再是檢查平等的簡單優化,它們不會嘗試檢查平等,只是標記小部件進行重新繪製。

+0

偉大的想法,但涉及的邏輯要求他們不幸在渲染循環中設置。有各種各樣的邏輯可以使事物的表現略有不同。儘管在渲染循環中創建邊框似乎是問題,但您確實處於正確的軌道上(請參閱我的答案)。不確定爲什麼。 – Morinar 2010-05-07 20:42:33

+1

設置這些項目的邏輯不需要在paint()方法中,將它們設置在paint方法之外將導致調用paint方法。考慮一下,當繪製東西時,你不會改變自己想要繪製的東西,因爲那樣你就需要重繪它。如果必須更改此標籤,則應在繪製標籤之前完成該標籤,然後該更改應該(正確)觸發重新繪製的需要。 – 2010-05-07 20:53:20

+0

我相信你是對的,但是這個代碼已經在生產了10年了,而且我不打算在事情上施加壓力。感謝您的邊界信息。 – Morinar 2010-05-07 21:48:11

0

這是邊界。在每個塗料循環過程中創建邊界,使其不斷重新繪製。如果我僅僅創建邊界作爲類作用域的私有對象並將其設置在繪製循環中,它將正確設置邊框並且不會持續重繪。如果有人知道爲什麼會有所作爲,我會很感激這個信息。請隨時對此發表評論,我會在我可以接受我的答案或者添加一個新的答案,並且我會接受你的答案。

2

請參閱JComponent.setBorder()中的代碼。它使用簡單的比較來比較新舊邊界 - 它們總是會返回假,因爲它們是兩個不同的對象。如果條件成立,組件將被重新粉刷。因此無限循環。

作爲一般規則 - 做而不是在其繪圖方法中調用組件上的任何setter。就像你看到的那樣,設置邊框會導致無限重繪循環。這可能會發生在任何其他設置下,如果不在此版本的VM中,可能在下一個設置中。做到這一點的正確方法是在模型更改時更改組件(視圖)的屬性,並讓Swing確定它何時將被重新繪製 - 或者自己調用repaint()。

+0

很酷,看到搖擺大師來到這裏。歡迎&thx幫助! – 2010-05-08 08:20:53