Search code examples
javaimageswingjlabelthread-sleep

How to change image of a JLabel in another thread


I want to make a Swing version TimeBomber, which means when time is counted down to 1 the Bomb will blow up! I have two images, images.png for a bomb in normal state, bomber.jpg for a bomb that has blown up. Apparently I need to change the images.png(which is already in an JLabel) to bomber.jpg when i==1; But I have no idea of how to change the pic location content in ImageIcon and as the change happens in anonymous inner class, so change value became difficult as final type var is not modifiable unless you call function.

public class TimeBomber {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        //create Jframe
        JFrame app = new JFrame("Time Bomber");

        //create JPanel
        final JPanel panel = new JPanel();

        //JLabel with first Picture
        JLabel pic = new JLabel(new ImageIcon("images.png"));
        pic.setSize(100, 100);
        //Label for displaying time digit
        final JLabel label = new JLabel("");
        label.setLocation(200, 250);
        //create another thread
        Thread time = new Thread(){
            public void run(){
                for(int i=10; i>0; i--){
                    if(i==1){
                        JLabel picSecond = new JLabel(new ImageIcon("Bomber.jpg"));
     //<--Fact is I dont want to create another JLabel, I want to modify the pic location content in JLabel pic.
                        picSecond.setSize(100, 100);

                        panel.add(picSecond);
                    }
                    label.setText("Time: "+i);
                    try {
                        sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        };

        //add every component to where it belongs
        panel.add(pic);
        panel.add(label);
        app.add(panel);
        app.setSize(300, 400);
        app.setVisible(true);
        app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        time.start();
    }

}

Solution

  • Wrap the code in SwingUtilities.invokeAndWait() (or SwingUtilities.invokeLater())

                if(i==1){
                    JLabel picSecond = new JLabel(new ImageIcon("Bomber.jpg"));//<--Fact is I dont want to create another JLabel, I want to modify the pic location content in JLabel pic.
                    picSecond.setSize(100, 100);
    
                    panel.add(picSecond);
                }
                label.setText("Time: "+i);
    

    TO avoid recreation of the JLabel make it the class' field and add to panel just once. Then use picSecond.setIcon() to update the image.

    BTW it's better to have kind of images cache to avoid image recreation on each step.