Matthew Flynn
Matthew Flynn

Reputation: 191

Graphics.drawImage from another Thread does not draw anything in Java Swing

I'm trying to draw an animation in a JPanel by displaying all the frames as BufferedImage objects and using a Thread to invoke g.drawImage in the JPanels paintComponent(Graphics g) method for each frame, with sleeping in between. My understanding is that invoking g.drawImage from anywhere, as long as g is the Graphics object from the paintComponent, should cause the pixels in the JPanel to be updated, but there is no change in the JPanel. Is that not how Graphics.drawImage works, or is it an issue with using another Thread, or something else all together? An abbreviated version of my code is below, with unnecessary bits removed

class Example extends JPanel{

    public Dimension getPreferredSize(){
        return new Dimension(500, 500);
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        draw(g);
    }

    public void draw(Graphics g){
        BufferedImage temp1;
        BufferedImage temp2;
        try{
            temp1 = ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\test1.png"));
            temp2 = ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\test2.png"));
        }catch(IOException e){
            temp1 = null;
            temp2 = null;
        }
        final BufferedImage image1 = temp1;
        final BufferedImage image2 = temp2;
        Thread drawThread = new Thread(new Runnable(){
            public void run(){
                g.drawImage(image1, 0, 0, null);
                try{
                    Thread.sleep(100);
                }catch(InterruptedException e){
                    // omitted
                }
                g.drawImage(image2, 0, 0, null);
                try{
                    Thread.sleep(100);
                }catch(InterruptedException e){
                    // omitted
                }
            }
        });
        drawThread.start();
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new B());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
           }
        });
    }

}

Upvotes: 1

Views: 694

Answers (1)

camickr
camickr

Reputation: 324197

Your current painting code is wrong. A painting method is for painting only. You would NEVER start a Thread from a painting method. You can't control when the painting method is invoked and every time the method is invoked you would start another Thread.

The Graphics object should only be used as a short duration object that exists for the duration of the painting method. You should not attempt to keep a reference to the object indefinitely.

I'm trying to draw an animation

If you want to do animation then you use a Swing Timer to schedule the animation.

So you should have the image as a property of the class. Then when the Timer fires you change the image property and invoke repaint() on the panel.

Upvotes: 1

Related Questions