【问题标题】:Java double buffer using an override for update method throws stack overflow使用覆盖更新方法的 Java 双缓冲区引发堆栈溢出
【发布时间】:2011-03-19 02:58:23
【问题描述】:

我试图通过覆盖我的 JPanel 的更新方法来实现我的游戏在 Java 中的双缓冲,我做了所有常用的代码等,但它仍然无法工作,它会引发堆栈溢出错误,下面是具体的错误:

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
        at java.awt.Rectangle.<init>(Rectangle.java:193)
        at java.awt.Rectangle.<init>(Rectangle.java:208)
        at sun.awt.image.BufImgSurfaceData.getBounds(BufImgSurfaceData.java:369)
        at sun.java2d.loops.GraphicsPrimitive.convertFrom(GraphicsPrimitive.java:533)
        at sun.java2d.loops.GraphicsPrimitive.convertFrom(GraphicsPrimitive.java:523)
        at sun.java2d.loops.MaskBlit$General.MaskBlit(MaskBlit.java:171)
        at sun.java2d.loops.Blit$GeneralMaskBlit.Blit(Blit.java:186)
        at sun.java2d.pipe.DrawImage.blitSurfaceData(DrawImage.java:927)
        at sun.java2d.pipe.DrawImage.renderImageCopy(DrawImage.java:550)
        at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:54)
        at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:982)
        at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2979)
        at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2964)
        at epicgame.Menu.displayMenu(Menu.java:71)
        at epicgame.GUI$1.paintComponent(GUI.java:64)
        at javax.swing.JComponent.paint(JComponent.java:1029)
        at epicgame.GUI$1.update(GUI.java:117)
        at epicgame.GUI$1.paintComponent(GUI.java:98)
        at javax.swing.JComponent.paint(JComponent.java:1029)

我的代码也不是特别复杂:

mainPanel = new JPanel()
        {
            @Override protected void paintComponent(Graphics g)
            {
                //super.paintComponent(g);

                if(menuEnabled == 1)
                {
                    Menu.displayMenu(g, mainPanel);
                }
                else if(gameNum == 1)
                { 
                    StreetFighter.StreetFighter(g, mainPanel);

                    // Calls the controls method within the controls class.
                    Controls.controls(Calendar.getInstance().getTimeInMillis() - timeOld);
                    timeOld = Calendar.getInstance().getTimeInMillis();
                }
                else if(gameNum == -1)
                {
                    Menu.scoreBoard(g, mainPanel);
                    if(loaded != true)
                    {
                        Menu.loadScoreBoard(mainPanel);
                        loaded = true;
                    }
                }
                if(gameNum > 0)
                {
                    if(longcat == true && longcatloaded != true)
                    {
                        Extras.loadLongCat();
                        longcatloaded = true;
                    }
                    if(longcatloaded == true && longcat == true)
                    {
                        Extras.displayLongCat(g, mainPanel);
                    }
                }

                // Causes an infinite loop, e.g makes the screen render over and over.
                //repaint();
                update(g);
            }

            @Override public void update(Graphics g)
            {
                System.err.println("Updating screen and using double buffer!");

                // initialize buffer
                if(dbImage == null)
                {
                    dbImage = createImage (this.getSize().width, this.getSize().height);
                    dbg = dbImage.getGraphics ();
                }
                // clear screen in background
                dbg.setColor (getBackground ());
                dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);
                // draw elements in background
                dbg.setColor (getForeground());

                paint(dbg);

                // draw image on the screen
                g.drawImage (dbImage, 0, 0, this);

                try
                {
                    Thread.sleep(200);

                }
                catch (InterruptedException ex)
                {
                    System.err.print("cant delay repaint.");
                }
            }
        };

我希望有人能指出我哪里出错了,我在想可能与更新被调用太多次有关,或者可能更新是错误的方法?

【问题讨论】:

    标签: java overriding stack-overflow doublebuffered


    【解决方案1】:

    不要从paintComponent() 调用paint() 或update() 方法。

    也不要在任何绘画方法中调用Thread.sleep()。相反,创建一个线程,每 x 毫秒更新一次游戏模型,然后在您已覆盖 paintComponent() 的自定义组件上调用 repaint(),以便绘制游戏状态。

    【讨论】:

    • 那么我会用什么来进行双缓冲?
    • +1 双缓冲是JPanel 的一个特性;只需使用相关的构造函数。这是example。
    【解决方案2】:

    您在组件的paintComponent 中调用paint,这将导致组件不断重新绘制自身。这将导致StackOverflowException。此外,API 告诫开发人员不要在应用程序中显式调用paint:

    由 Swing 调用以绘制组件。 应用程序不应调用绘画 直接,但应改为使用 重绘方法来安排 用于重绘的组件。

    这个方法实际上是委托 绘画作品三保护 方法:paintComponent、paintBorder、 和绘画儿童。他们被召唤进来 列出的顺序,以确保 孩子出现在组件的顶部 本身。一般来说, 组件及其子组件不应 在分配给的插图区域中绘画 边界。子类可以 像往常一样覆盖这个方法。一个 只想专攻的子类 UI(外观和感觉)委托的 油漆方法应该只是覆盖 油漆组件。

    【讨论】:

    • 我需要这个,因为我整个游戏的基础依赖于它的不断刷新。 ://
    • @Luke:一种方法是检查变量gameNum 和menuEnabled,只要它们的值发生更改(或通过使用计时器或执行程序服务定期)。如果它们满足某个条件,则设置一个global 标志并随后调用repaint(可能还有removeAll 之前)。然后,检查 paintComponent 中的标志并执行适当的绘图。
    • 谢谢,我以后会考虑的。
    【解决方案3】:

    您需要在完成后每帧调用g.dispose(),否则它将永远不会从内存中释放,并且您会看到堆栈溢出错误。 http://download.oracle.com/javase/1.3/docs/api/java/awt/Graphics.html

    【讨论】:

    • 在我的更新方法的底部添加这个之后,我仍然收到堆栈溢出。帮助。
    • “仅当它是直接从组件或另一个 Graphics 对象创建时才需要”。此外,引用更新的 API 可能会有所帮助。
    • API 链接是第一个 Google 结果,很确定它仍然适用。不确定何时需要处理的细节,但如果您在 Java 中进行双缓冲,则您正在进行主动渲染(而不是被动渲染),这需要您在每帧渲染后手动调用 dispose() .
    • 这两个链接都表明clear 在这种情况下您的建议是错误的。
    猜你喜欢
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多