2013-06-25 147 views
1

我已經在JScrollPane中放置了一個JPanel對象,並且滾動按預期工作。通過覆蓋paintComponent()我試圖在JPanel對象內做自定義繪畫。但是,當JPanel對象放置在JScrollPane中時,JPanel不再正確繪製(僅顯示其背景顏色)。JScrollPane中的JPanel繪畫問題

因爲我的應用程序要求不斷更新JPanel,所以構造一個單獨的線程以在特定間隔重新繪製JPanel。

下面的代碼摘錄顯示我的當前項目:

A)的paintComponent()從我的JPanel(這種方法已經被削減到只有繪畫,實際油漆會從另一個提供一個不斷更新的BufferedImage線程代替這個大靜態粉框):

@Override 
public void paintComponent(Graphics g){ 
    super.paintComponent(g); 

    //Render Frame 
    // 'RXDisplayCanvas' is the JPanel. 
    Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics(); 

    G2D.setColor(Color.PINK); 
    //800 and 600 are arbitrary values for this example, real values are calculated at runtime. The value calculation code is verified to work (as its used elsewhere in a similar scenario) 
    G2D.fillRect(0, 0, 800, 600); 
    G2D.dispose(); 
} 

b)中所述的 '更新' 線程週期性地重畫幀:

@Override 
public void run() { 
    long MaxFrameTime; 
    long Time; 

    while(isVisible()){ 
     // 'FPSLimit' is a integer value (default to 30) 
     MaxFrameTime = Math.round(1000000000.0/FPSLimit); 
     Time = System.nanoTime(); 

     try{ 
      SwingUtilities.invokeAndWait(new Runnable(){ 
       @Override 
       public void run() { 
        // 'RXDisplayCanvas' is the JPanel. 
        RXDisplayCanvas.repaint(); //When using this, the JPanel does not display correctly. 

        //RXDisplayCanvas.paintImmediately(0, 0, RXDisplayCanvas.getWidth(), RXDisplayCanvas.getHeight()); When using this, the JPanel renders correctly but flickers. 
       } 
      }); 
     }catch(InterruptedException | InvocationTargetException e){} 

     Time = System.nanoTime() - Time; 
     if(Time < MaxFrameTime){ 
      try{ 
       Thread.sleep(Math.round((MaxFrameTime - Time)/1000000.0)); 
      }catch(InterruptedException ex){} 
     } 
    } 
} 

我已經考慮到repaint()不會立即重畫屏幕,但問題在於屏幕顯示不正確。當程序獨立時,它只是呈現JPanel的背景顏色,直到JScrollPane滾動爲止,然後在下一次重繪()調用繪製不正確的顯示之前,它爲一幀正確渲染。

當切換重繪()出來paintImmediately()(在摘錄b)中正確地呈現,但重閃爍存在的幀,其中它不斷地繪製背景顏色和繪畫粉箱之間交替。我嘗試添加和刪除佈局管理器,禁用重繪管理器,並啓用和禁用所有導致上述兩種行爲之一(僅渲染背景或閃爍)的兩個組件的「雙緩衝」標誌。

任何人都可以幫助我解決這個問題嗎?我很清楚Java的變量命名約定,因爲這是一個私人項目,我選擇用大寫字母來啓動變量名,因爲我認爲它看起來更好,請不要發表評論。

+1

如何同步訪問共享數據? – trashgod

+0

不再相關,但用另一個將BufferedImage的柵格複製到活動顯示緩衝區的線程完成。顯示不斷顯示當前的BufferedImage,而另一個線程更新它(全部使用同步塊完成)。 – initramfs

回答

7

1)我不知道這一點:

public void paintComponent(Graphics g){ 
    super.paintComponent(g); 
    // 'RXDisplayCanvas' is the JPanel. 
    Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics(); 
    .. 
    G2D.dispose(); 
} 

我建議做:

public void paintComponent(Graphics g){ 
    super.paintComponent(g); 
    Graphics2D G2D = (Graphics2D)g; 
    G2D.setColor(Color.PINK); 
    G2D.fillRect(0, 0, 800, 600); 
} 

注意我如何省略了getGraphics,並使用在paintComponent圖形上下文中流過的電流。

另外請注意,我不叫g2d.dipose()因爲這會導致問題,它應該是它已經被創建並傳遞只在您創建Component.getGraphics()但在你的情況下,你甚至不應該創建Graphic的上下文Graphic S DONE在paintComponent方法中。 (參見this類似的問題)

2)因爲它是線程安全的,所以不需要SwingUtilities.invokeXXXrepaint()。但特別是不需要SwingUtilities.invokeAndWait(因爲這是一個阻塞調用,並等待所有待處理的AWT事件得到處理並且run()方法完成),這並不好,也可能會增加您看到的屏幕上的視覺工件。

3)我嘗試添加和刪除佈局管理器,禁用重繪管理器以及啓用和禁用所有導致上述兩種行爲之一的兩個組件的「雙緩衝」標誌(僅渲染背景或閃爍)。撤消所有這一切,因爲我不明白這是如何影響畫。

如果我有一個說明不需要的行爲的SSCCE會更有幫助。正如我可以嘗試重現您的錯誤,但我最有可能不會能夠(由於適用於您的應用程序的具體情況,可能導致這些視覺文物)

+2

噢,我的上帝......我怎麼會錯過? Graphics2D G2D =(Graphics2D)g; 取而代之的是: (Graphics2D)RXDisplayCanvas.getGraphics(); 這真的解決了我的問題,我非常感謝你注意到這個小錯誤,我沒有注意到3天... – initramfs

+1

@CPUTerminator沒有問題,有時我們只需要第二雙眼睛:) –

+1

完全同意: ) – initramfs