JPanel in puzzle game not updating

6

I have a simple puzzle game. There is an image consisting of 16 tiles (randomly placed). Images are stored in an array and when game is launched they're added to main JPanel.

alt text

Game works in this way : Each image has atributes 'place' and 'number'. 'Place' is the current place on grid (either correct or not) and 'number' is the desired place for the image. When a user clicks image their 'place' and 'number' attributes are checked. If they match nothing happens. If not game checks if any image is currently in memory. If there is none, then this image's 'place' and 'number' are stored. If there is some image in memory, then the currently clicked image's 'plac'e is checked with stored image's 'number'. When they match - their places are exchanged. This part works properly. But now, I'm calling addComponent method on my JPanel with updated images and simply nothing happens. Shouldn't the new images be added to JPanel replacing the old ones ?

package Bonus;

import javax.swing.*;
import java.util.Random;
import java.awt.event.*;
import java.awt.*;

class Puzzle extends JPanel implements ActionListener {
    private int selected_nr=-1;
    private int selected_pl=-1;
    private boolean memory=false;
    private static Img[] images;

    public Puzzle(){
        JFrame f = new JFrame("Smile");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.setSize(252,252);
        f.setVisible(true);

        setLayout(new GridLayout(4, 4));
        images = new Img[16];
        int[] buttons = new int[16];

        for(int i=0; i<16; i++){
            buttons[i] = i;
        }

        int rand;
        int temp;
        Random random;

        random = new Random(System.currentTimeMillis());
        for (int i = 0; i < buttons.length; i++) {
            rand = (random.nextInt() & 0x7FFFFFFF) % buttons.length;
            temp = buttons[i];
            buttons[i] = buttons[rand];
            buttons[rand] = temp;
        }

        for (int i = 0; i < 16; i++) {
            images[i] = new Img(i, buttons[i]);
        }
        addComponents(images);
    }

    public void addComponents(Img[] im){
        this.removeAll();
        for(int i=0; i<16; i++){
            im[i].addActionListener(this);
            im[i].setPreferredSize(new Dimension(53,53));
            add(im[i]);
        }
        this.validate();
    }

    public void actionPerformed(ActionEvent e) {
        Img b = (Img)(e.getSource());
        int num = b.getNumber();
        int pl = b.getPlace();

        if(!(b.rightPlace())){
            if(memory){
                if(pl == selected_nr){
                    images[pl].setPlace(selected_pl);
                    images[selected_pl].setPlace(selected_nr);
                    selected_nr = -1;
                    selected_pl = -1;
                    memory = false;
                    addComponents(images);
                }
                else{
                    System.out.println("Try other image");
                }
            }
            else{
                memory = true;
                selected_nr = num;
                selected_pl = pl;
            }
        }
        else{
            System.out.println("OK !");
        }
    }

    public static void main(String args[]) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Puzzle();
            }
        });
    }
}

class Img extends JButton {
    int number;
    int place;
    ImageIcon img;

    public Img(int p, int n){
        number = n;
        place = p;
        img = new ImageIcon("u"+number+".jpg", BorderLayout.CENTER);
        setIcon(img);
    }

    public boolean rightPlace(){
        boolean correct=false;
        if(number == place){
            correct = true;
        }
        return correct;
    }
    public void setPlace(int i){
        place = i;
    }
    public int getNumber(){
        return number;
    }
    public int getPlace(){
        return place;
    }
}

EDIT: Changed the code to use the answers, but still no luck. addComponents() gets updated images[] but doesn't revalidate them.

java
swing
asked on Stack Overflow Jun 20, 2010 by DevAno1 • edited Jul 30, 2019 by Glorfindel

3 Answers

12

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();
            }
        });
    }
}
answered on Stack Overflow Jun 20, 2010 by trashgod • edited Sep 14, 2012 by trashgod
4

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.

answered on Stack Overflow Jun 20, 2010 by akf
3

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

answered on Stack Overflow Jun 20, 2010 by Frederick

User contributions licensed under CC BY-SA 3.0