开发者

Java double buffer using an override for update method throws stack overflow

I am trying to achieve double buffering of my game in Java by overriding the update method for my JPanel, I do all the usual code etc and still it won't work, it throws a stack overflow error, below is the specific error:

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)

My code isn't particularly complex either:

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.");
                }
            }
        };

I was hoping someone could point out where I went wrong, I'm thinking maybe something to do with the update being called too many times, or possible update is the wrong method?


Don't call paint() or update() methods from paintComponent().

Also don't call Thread.sleep() in any painting methods. Instead, create a thread that updates your game model every x milliseconds and then calls repaint() on your custom component where you have overridden paintComponent() so that it draws the game state.


You're calling paint within the component's paintComponent, which will cause the component to keep repainting itself. This will cause a StackOverflowException. Also, the API admonishes a developer about explicitly invoking paint in an application:

Invoked by Swing to draw components. Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.

This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren. They're called in the order listed to ensure that children appear on top of component itself. Generally speaking, the component and its children should not paint in the insets area allocated to the border. Subclasses can just override this method, as always. A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.


You need to call g.dispose() every frame after you are done with it, otherwise it will never be released from memory and you get the stack overflow error you see. http://download.oracle.com/javase/1.3/docs/api/java/awt/Graphics.html

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜