JScrollPane绘图问题中的JPanel

ini*_*mfs 1 java swing jpanel jscrollpane paintcomponent

我已经在JScrollPane中放置了一个JPanel对象,并且滚动按预期工作.通过覆盖paintComponent(),我试图在JPanel对象中进行自定义绘制.但是,当JPanel对象放在JScrollPane中时,JPanel不再正确绘制(而只显示其背景颜色).

因为我的应用程序要求不断更新JPanel,所以构造一个单独的线程以特定间隔重新绘制JPanel.

以下代码摘录显示了我当前的项目:

a)来自我的JPanel的paintComponent()(此方法已被裁减为仅绘画,实际绘制将是从另一个线程而不是这个大粉红色静态框提供的不断更新的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();
}
Run Code Online (Sandbox Code Playgroud)

b)定期重新绘制帧的'updater'线程:

@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){}
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经考虑到repaint()不会立即重新绘制屏幕,​​但问题在于屏幕呈现错误.当程序独立时,它只渲染JPanel的背景颜色,直到滚动JScrollPane,在下一次repaint()调用绘制错误显示之前,它正确呈现一帧.

当为paintImmediately()(在摘录b中)切换repaint()时,框架正确渲染但存在大量闪烁,其中它在绘制背景颜色和绘制粉红色框之间不断交替.我尝试添加和删除布局管理器,禁用重绘管理器以及启用和禁用两个组件的"双缓冲"标志,其中所有组件都导致上述两种行为之一(仅渲染背景或闪烁).

任何人都可以帮我解决这个问题吗?

注意:我很清楚Java的变量命名约定,因为这是一个私有项目,我选择用大写字母开始变量名,因为我觉得它看起来更好,请不要发表评论.

Dav*_*amp 7

1)我不确定这个:

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

我建议做:

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

注意我是如何省略的getGraphics,并使用当前在图形上下文中传递的paintComponent.

另请注意,我不调用g2d.dipose()因为这会导致问题,它应该只在Graphic您创建的s 上完成,Component.getGraphics()但在您的情况下,您甚至不应该创建Graphics上下文,因为它已经创建并传递给paintComponent方法.(见这个类似的问题)

2)不需要SwingUtilities.invokeXXX块,repaint()因为它是线程安全的.但特别是不需要SwingUtilities.invokeAndWait(因为这是一个阻塞调用并等待所有待处理的AWT事件被处理并且run()方法完成)这是不好的,也可能是添加到你看到的屏幕上的视觉文物.

3)我尝试添加和删除布局管理器,禁用重绘管理器以及启用和禁用两个组件的"双缓冲"标志,其中所有组件都导致上述两种行为之一(仅渲染背景或闪烁).撤消所有这些,因为我看不出它如何影响这幅画.

如果我有一个说明不需要的行为的SSCCE会更有帮助.因为我可以尝试重现您的错误但我很可能无法(由于适用于您的应用程序的特定条件可能导致这些视觉文物)

  • 我的天啊......我怎么能错过那个?Graphics2D G2D =(Graphics2D)g; 而不是:(Graphics2D)RXDisplayCanvas.getGraphics(); 这确实解决了我的问题,我非常感谢你注意到我在3天内没有注意到的这个小错误...... (2认同)