2011-05-26 24 views
2

我不太確定如何說明這一點,請耐心等待。java + Swing:矩形或其他「精靈」的高效疊加

我有兩個JPanel s在一個容器JPanelOverlayLayout。容器中的JPanel s覆蓋paint(Graphics)

底部JPanel是不透明的,並繪製一些相當複雜的圖形,因此需要「很長」的時間(10s或100s毫秒)來呈現。

頂部JPanel是透明的,只是繪製一個矩形或行或基於鼠標輸入簡單的形狀,所以它的真快。

有沒有辦法設置,所以當我改變上面板的簡單形狀,它不重繪底部面板?(例如,它以某種方式緩存底部面板)

我很熟悉w /像bitblt,雙緩衝和異或繪圖的概念,但不知道在這裏應用什麼。

回答

4

你最好關閉使用單一JComponent和創建BufferedImage存儲底部的圖像。當paintComponent操作發生在JComponent上時,您只需拍攝底部圖像,然後使用Graphics對象對其進行繪製(從存儲狀態開始)。應該相當有效。

你會想在另一個線程中對底部BufferedImage進行復雜的繪製操作,因爲另一個海報提到(忽略這個意外,對不起:))。但是,您不希望在該圖像上引起爭用,因此您必須爲此另存爲BufferedImage,並在完成繪圖操作的同時,將其同步到其他圖像上。

3

着眼複雜面板上,關鍵是除了drawImage()融通東西展現出來的paintComponent()。將其他所有內容放在另一個線程中,以不斷更新屏幕外緩衝區。以一定的速率定期更新屏幕,以保持簡單面板的響應。唯一困難的部分是同步,但SwingWorker是一個不錯的選擇。還有更多here

3

什麼肯定的是,如果上面板的目標是一個完整的repaint(),那麼下一個會是也。

也許你可以嘗試優化區域重畫上面板上,以避免重畫所有較低的一個。但是,如果上面板上的彩色矩形覆蓋整個區域,那麼您將再次以完整的repaint()結束。

通常情況下,Swing會嘗試優化需要重繪的區域,但在短時間內執行多次重繪時也會聚合這些區域,如果我沒記錯,聚合區域只是一個矩形,即聯合的所有重繪矩形,這並不總是優化,但允許快速計算重繪事件創建。

現在,我想你應該按照以前的回覆中給出的建議;事實上,你應該避免擁有一個可以執行長時間計算的方法(幾十ms應該是真正的最大值)。如果不想讓GUI看起來對最終用戶沒有反應,繪畫應儘可能快。因此,贊成只進行一次計算(如果可能的話,在EDT之外)將結果存儲在BufferedImage中,您只需稍後在paint()方法中繪製即可。

編輯:增加反映其它來源

如果要優化點列表的更新,但仍保持在paint()方法,那麼你可以使用通過Graphics的剪輯區域限制調用繪圖方法,是這樣的:

Rectangle clip = g.getClipBounds(); 
for (Point p: allPoints) { 
    if (clip.contains(p)) { 
     // draw p with g graphics 
    } 
} 

你甚至可以嘗試優化點列表使用QuadTree,而不是一個簡單的List畫畫,但你必須自己編寫它(或找 一些免費的實現,可能有一些在那裏)。使用四叉樹時,您可以優化時間以查找必須重繪的所有點的列表(基於Graphics裁剪矩形),並僅重繪這些點。

+0

聽起來像是不錯的想法。這不是說它有很多計算,而是我繪製了數萬個點。 – 2011-05-27 00:44:30

+0

是的,但是繪製1000點的10點會使用大量的CPU。所以將它們繪製在paint()之外的'BufferedImage'上並且僅在點列表(或者它們的座標)改變時才更新'BufferedImage',在重建'BufferedImage'之後,你只需要調用'重繪()'。 – jfpoilpret 2011-05-27 04:36:48

2

附錄由trashgod和jfpoilpret答案

1/OverlayLayout是奇怪的方式如何佈局JPanels,你同樣的輸出與曾經的JPanel(不OverlayLayout和Translucentcy)

2 /(10S或100S毫秒)可能很小,因爲有Native OS延遲(今天的操作系統和PC爲45-75ms)

3 /同步將通過在後臺任務上使用SwingWorker進行管理,並且通過使用後臺繪圖進程的順序,指示和同步來管理JPanel,也許你的油漆太快/太快

4 /你沒有介紹更多有關如何,在何處以及其中約油漆()/的paintComponent()

if (SwingUtilities.isEventDispatchThread()) { 
     paintImmediately(int x, int y, int w, int h) // or Rectangle r 
    } else { 
     Runnable doRun = new Runnable() { 

      @Override 
      public void run() { 
       repaint(long tm, int x, int y, int width, int height) // or Rectangle r 
      } 
     }; 
     SwingUtilities.invokeLater(doRun); 
    } 
+0

這些都是好的問題。 – trashgod 2011-05-27 15:46:08