简体   繁体   中英

Why does my draw method only work some of the time?

I know that in swing you are meant to use repaint to redraw a panel, but I am starting to make games and have read that repaint is unreliable in terms of timing. So I am trying to make a strategy where I create a BufferedImage, draw every thing I need to that objects graphics object and then draw the image to my jpanel using drawImage method.

I am calling dispose to get the panel to re-render, but its only working some of the time. The following is just an example. If you keep running this program, the BufferedImage only gets drawn ~3/10 times you run it. Can someone explain this to me please?

public class TestMain {

public static void main(String[] args) throws InterruptedException {

    JFrame jf = new JFrame();
    MyPanel mp = new MyPanel();
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setLocation(50, 500);
    jf.add(mp);
    jf.pack();
    jf.setVisible(true);

    mp.draw();
}
}

public class MyPanel extends JPanel {

private static final long serialVersionUID = 1L;

BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d;

public MyPanel() {
    super();
    setPreferredSize(new Dimension(300, 300));
}

public void draw() {
    System.out.println("In draw");
    g2d = (Graphics2D) img.getGraphics();
    g2d.drawString("Test", 10, 10);

    Graphics g = getGraphics();

    g.drawImage(img, 0, 0, this);
    g.dispose();
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    System.out.println("In paintComponent");
}

}

What am I battling with here behind the scenes that is blocking the draw more often than not. I realise that resizing the window, etc. will call repaint and override my drawing but when I don't do that it should show up every time, no?

Edit: interesting... if I wrap the draw method in a continuous while loop it "works". But this doesn't answer my question. I shouldn't need to constantly recall the method to give the illusion that it's drawing ok.

You should not use the getGraphics() method to do painting. Any code you do with getGraphics is only temporary and will be lost whenever Swing determines the component needs to be repainted, which is probably happening here.

Override the getPreferredSize() method of your class and invoke super.paintComponent() and then add a System.out.println(...) statement. Also, add a System.out.println(...) statement to the draw() method to see the order of execution of the code.

I am calling dispose to get the panel to re-render,

That won't cause the panel to render, it just frees the resources allocated to the Graphics object. You need to invoke the draw() method to continually repaint.

This is essentially the same as using a Timer to continually repaint() the component. The difference is the that the draw() might happen right away, but the repaint might take a few milliseconds. But since repaint() takes a few ms every time the interval will remain constant, its not like repaint will paint once and then wait a second the next time.

I fixed your code and got the following GUI:

在此处输入图片说明

When you paint on a buffered image, you have to do everything. You have to paint the background and paint the foreground.

When you paint the buffered image in the paintComponent method of a JPanel, all you have to do is draw the image.

The Swing paintComponent method is fast enough in Java versions 6, 7, and 8 to paint without flickering. I've done animations with tens of thousands of lines with no flicker.

You must start a Swing application on the Event Dispatch thread by calling the SwingUtilities invokeLater method.

Here's your modified code.

package com.ggl.testing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestMain implements Runnable {

    @Override
    public void run() {
        JFrame jf = new JFrame();
        MyPanel mp = new MyPanel();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLocation(50, 50);
        jf.add(mp);
        jf.pack();
        jf.setVisible(true);
        mp.draw();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TestMain());
    }

    public class MyPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        BufferedImage img = new BufferedImage(100, 100,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d;

        public MyPanel() {
            super();
            setPreferredSize(new Dimension(300, 300));
        }

        public void draw() {
            System.out.println("In draw");
            g2d = (Graphics2D) img.getGraphics();
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
            g2d.setColor(Color.BLACK);
            g2d.drawString("Test", 30, 50);
            g2d.dispose();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("In paintComponent");
            g.drawImage(img, 0, 0, this);
        }

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM