2013-06-25 68 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