JPanel в игре-головоломке не обновляется

У меня есть простая игра-головоломка. Существует изображение, состоящее из 16 плиток (размещенных случайным образом). Изображения хранятся в массиве, и при запуске игры они добавляются в основной JPanel.

http://img248.imageshack.us/img248/7403/27632947.gif

Игра работает следующим образом: каждое изображение имеет атрибуты "место" и "номер". "Место" - текущее место на сетке (правильное или нет), а "число" - желаемое место для изображения. Когда пользователь нажимает на изображение, проверяются его атрибуты "место" и "номер". Если они совпадают, ничего не происходит. Если нет, игра проверяет, находится ли какое-либо изображение в памяти. Если их нет, то "место" и "номер" этого изображения сохраняются. Если в памяти есть какое-то изображение, тогда 'plac'e' текущего кликаемого изображения проверяется с 'номером' сохраненного изображения. Когда они совпадают - их места меняются. Эта часть работает правильно. Но сейчас я вызываю метод addComponent на моем JPanel с обновленными изображениями, и просто ничего не происходит. Не следует ли добавлять новые изображения в JPanel вместо старых?

пакет Бонус;

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;
    }
}

РЕДАКТИРОВАТЬ: изменил код, чтобы использовать ответы, но все равно не повезло. addComponents () получает обновленные изображения [], но не проверяет их заново.

3 ответа

Решение

После изменения компонентов вам необходимо "обновить" компонент Swing, вызвав invalidate() или же revalidate(),

Вместо того, чтобы полагаться на предварительно вырезанные файлы изображений, вот пример нарезки существующего изображения и перетасовки результирующих частей. Он объединяет полезные (+1) предложения как @Frederick, так и @akf.

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();
            }
        });
    }
}

Вы снова добавляете все свои компоненты в JPanel, фактически не удаляя ни одного из них. В вашем addComponents() метод, я бы сначала позвонил removeAll(), Возможно, вы захотите переименовать этот метод, чтобы выделить побочные эффекты, так как он больше не будет только добавлять компоненты. Может быть, resetComponents() было бы лучше.

Другие вопросы по тегам