BraveHeart
BraveHeart

Reputation: 331

Java Swing drawing wrong pictures due to delay

I'm new to swing progarmming and im having some difficulties with the thread synchronisation.

I'm trying to iterate over an array and create a JPanel and a JFrame at every index and want to paint a picture on each panel. A picture which is related to the value stored in the array. But all the frames/panels only hold the picture for the last array entry. I assume this is due to a seperate swing-Thread(?), but I dont know how to change it. Can You help me?

package help;

import java.awt.Graphics;
import java.awt.image.BufferedImage; 
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SwingSynchro{

private JPanel jPanel;
private JFrame jFrame;
int array[] = {1,2,3,4};
int current;
private BufferedImage image1;
private BufferedImage image2;
private BufferedImage image3;
private BufferedImage image4;

public SwingSynchro(){

    //try{
    //    image1 = ImageIO.read(new File("someFilePath1.png"));
    //    image2 = ImageIO.read(new File("someFilePath2.png"));
    //    image3 = ImageIO.read(new File("someFilePath3.png"));
    //    image4 = ImageIO.read(new File("someFilePath4.png"));
    //} catch(IOException e){
    //    e.printStackTrace();
    //    System.out.println("wrong file path");
    //}// try catch

    for(int i = 0 ; i < array.length ; i++){

        current = array[i];
            System.out.println("current Number: "+ current + " at array index:" +i);

            jPanel = new JPanel(){
                private static final long serialVersionUID = 6859593162185621113L;

                @Override
                protected void paintComponent(Graphics g){
                    super.paintComponent(g);

                    switch(current){
                        case 1:
                            System.out.println("case 1");
                            //g.drawImage(image1, 10, 10, getWidth() - 20, getHeight() - 20, this);
                            break;
                        case 2:
                            System.out.println("case 2");
                           // g.drawImage(image2, 20, 20, getWidth() - 40, getHeight() - 40, this);
                            break;
                        case 3:
                            System.out.println("case 3");
                            //g.drawImage(image3, 10, 10, getWidth() - 20, getHeight() - 20, this);
                            break;
                        case 4:
                            System.out.println("case 4");
                            //g.drawImage(image4, 10, 10, getWidth() - 20, getHeight() - 20, this);
                            break;
                        default:
                            System.out.println("RELEASE THE KRAKEN!");
                            break;
                    }// switch
                }// paintComponent()
            };// anonymous class(extends JPanel)


        jFrame = new JFrame(String.valueOf(current));
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setResizable(false);
        jFrame.getContentPane().add(jPanel);
        jFrame.setSize(200, 250);
        jFrame.setLocation(i * 203, 0);
        jFrame.setVisible(true);
    }
}
}

I commented out the pictures because the console output you can clearly see that the drawImage method gets called after the whole for loop.

Edit: It looks like there is no other Thread, but in that case I dont understand why the drawings(or the case statements) have this delay. Can You explain to me why the code is not executed as usual.

Here is the output:

current Number: 1 at array index:0
current Number: 2 at array index:1
current Number: 3 at array index:2
current Number: 4 at array index:3
case 4
case 4
case 4
case 4

Upvotes: 1

Views: 141

Answers (2)

Zolt&#225;n
Zolt&#225;n

Reputation: 22156

Instead of instantiating the JPanel as an anonymous class, you could make it an inner class and use fields to hold the value of your current variable.

private static class CustomJPanel extends JPanel {
    private static final long serialVersionUID = 6859593162185621113L;
    private final int current;

    private CustomJPanel(int current) {
        this.current = current;
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);

        switch(current){
            case 1:
                System.out.println("case 1");
                //g.drawImage(image1, 10, 10, getWidth() - 20, getHeight() - 20, this);
                break;
            case 2:
                System.out.println("case 2");
                // g.drawImage(image2, 20, 20, getWidth() - 40, getHeight() - 40, this);
                break;
            case 3:
                System.out.println("case 3");
                //g.drawImage(image3, 10, 10, getWidth() - 20, getHeight() - 20, this);
                break;
            case 4:
                System.out.println("case 4");
                //g.drawImage(image4, 10, 10, getWidth() - 20, getHeight() - 20, this);
                break;
            default:
                System.out.println("RELEASE THE KRAKEN!");
                break;
        }// switch
    }// paintComponent()
}

and then just instantiate it as

jPanel = new CustomJPanel(current);

This way, you're making sure that it's been passed the value that the current variable had when the JPanel was instantiated.

Upvotes: 2

0x6C38
0x6C38

Reputation: 7076

Swing is single threaded. Use a Swing Timer if you want to see updates to your GUI in real time.

Upvotes: 2

Related Questions