JPanel in puzzle game not updating

Solution 1:

Rather than relying on precut image files, here's an example of slicing an existing image and shuffling the resulting pieces. It combines the helpful (+1) suggestions of both @Frederick and @akf.

enter image description here

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ImageLabelPanel extends JPanel implements ActionListener {

    private static final int N = 4;
    private final List<JLabel> list = new ArrayList<JLabel>();
    private final Timer timer = new Timer(1000, this);

    ImageLabelPanel() {
        this.setLayout(new GridLayout(N, N));
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(new File("image.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                int w = bi.getWidth() / N;
                int h = bi.getHeight() / N;
                BufferedImage b = bi.getSubimage(c * w, r * h, w, h);
                list.add(new JLabel(new ImageIcon(b)));
            }
        }
        createPane();
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setVisible(true);
        timer.start();
    }

    private void createPane() {
        this.removeAll();
        for (JLabel label : list) add(label);
        this.validate();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Collections.shuffle(list);
        createPane();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ImageLabelPanel();
            }
        });
    }
}

Solution 2:

You are adding all of your components again to your JPanel without actually removing any of them. In your addComponents() method, I would first call removeAll(). You might want to rename that method to highlight the side-effects, as it no longer would only be adding components. Perhaps, resetComponents() would be better.

Solution 3:

After changing the components, you need to 'refresh' the Swing component by calling invalidate() or revalidate().