Java swing odświeżanie jPanel

witam, chce napisać grę Sokoban, zrobiłem plansze, zaimplementowałem obsługę klawiatury, mam problem z odświeżeniem planszy po przesunięciu kwadratu. Napisałem trzy klasy: JavaSwingSokoban w której jest robione okno, ClassBoard w która odpowiada za rysowanie planszy, i ClassMove która odpowiada za obsługę klawiatury. Jest opcja żeby użyć Timera i odświeżać co określony czas ale to bez sensu trochę, chcę żeby się odświeżało co kliknięcie odpowiedniego klawisza odpowiadającego za poruszanie. bardzo proszę o podpowiedzi i o uwagi dotyczące kodu, nie jest to projekt na jakieś zaliczenie, o to kod:

/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package javaswingsokoban;


import java.awt.Dimension;

import java.awt.Point;

import javax.swing.JFrame;

import javax.swing.SwingUtilities;


/**

 *

 * @author marcin

 */

public class JavaSwingSokoban{


    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {


            @Override

            public void run() {

                JFrame jFrame = new JFrame();

                int widthWindow = 660;

                int heightWindow = 500;

                jFrame.setTitle("sokoban !!");

                jFrame.setLocation(new Point(100, 100));

                jFrame.setSize(new Dimension(widthWindow, heightWindow));

                jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                jFrame.setResizable(false);

                jFrame.setVisible(true);

                ClassBoard classBoard = new ClassBoard();

                jFrame.add(classBoard);

            }


        });

    }

}


/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package javaswingsokoban;


import java.awt.Color;

import java.awt.Graphics;

import javax.swing.JPanel;


/**

 *

 * @author marcin

 */

public class ClassBoard extends JPanel{


    ClassMove classMove = new ClassMove();

    private int sizeSquare = 40;

    private int positionX = 50;

    private int positionY = 50;


    //0 - mur czarny

    //1 - puste pole bialy

    //2 - pudelko zielony

    //3 - ludzik czerwony

    static int[][] plansza = {

        {0,0,0,0,0,0,0,0,0,0,0,0,1,1},

        {0,1,1,1,1,0,1,1,1,1,1,0,0,0},

        {0,1,1,1,1,0,1,2,1,1,2,1,1,0},

        {0,1,1,1,1,0,2,0,0,0,0,1,1,0},

        {0,1,1,1,1,1,1,1,1,0,0,1,1,0},

        {0,3,1,1,1,0,1,0,1,1,2,1,0,0},

        {0,0,0,0,0,0,1,0,0,2,1,2,1,0},

        {1,1,0,1,2,1,1,2,1,2,1,2,1,0},

        {1,1,0,1,1,1,1,0,1,1,1,1,1,0},

        {1,1,0,0,0,0,0,0,0,0,0,0,0,0}

    };


    public ClassBoard() {

        this.setFocusable(true);

        addKeyListener(classMove);

    }


    @Override

    public void paint(Graphics graphics){

        drawBoard(graphics);

    }


    void drawBoard(Graphics graphics){

        super.paint(graphics);

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

            for(int j = 0; j < plansza[0].length; ++j){

                if(plansza[i][j] == 0){

                    graphics.setColor(Color.BLACK);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);

                } else if(plansza[i][j] == 1){

                    graphics.setColor(Color.WHITE);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);

                } else if(plansza[i][j] == 2){

                    graphics.setColor(Color.GREEN);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);

                } else if(plansza[i][j] == 3){

                    graphics.setColor(Color.RED);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);                    

                }

            }

        }

    }


}


/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package javaswingsokoban;


import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;


/**

 *

 * @author marcin

 */

public class ClassMove implements KeyListener{


    private int x = 5;

    private int y = 1;


    @Override

    public void keyTyped(KeyEvent e) {

    }


    @Override

    public void keyPressed(KeyEvent keyEvent) {

        switch(keyEvent.getKeyCode()){

            case KeyEvent.VK_UP:

                if(ClassBoard.plansza[x - 1][y] == 1){

                    ClassBoard.plansza[x - 1][y] = 3;

                    ClassBoard.plansza[x][y] = 1;

                    x--;

                }

                System.out.println("wcisles up");

                break;

            case KeyEvent.VK_DOWN:

                System.out.println("wcisles down");

                if(ClassBoard.plansza[x + 1][y] == 1){

                    ClassBoard.plansza[x + 1][y] = 3;

                    ClassBoard.plansza[x][y] = 1;

                    x++;

                }

                break;

            case KeyEvent.VK_LEFT:

                System.out.println("wcisles left");

                if(ClassBoard.plansza[x][y - 1] == 1){

                    ClassBoard.plansza[x][y - 1] = 3;

                    ClassBoard.plansza[x][y] = 1;

                    y--;

                }

                break;

            case KeyEvent.VK_RIGHT:

                System.out.println("wcisles right");

                if(ClassBoard.plansza[x][y + 1] == 1){

                    ClassBoard.plansza[x][y + 1] = 3;

                    ClassBoard.plansza[x][y] = 1;

                    y++;

                }

                break;

        }

    }


    @Override

    public void keyReleased(KeyEvent e) {

    }

}

[/code]

wrzuciłem ten twój kod w IDE i po paru poprawkach ruszyło. Wydaje mi się że rozbicie na 3 klasy nie jest tutaj poprawne. Połączyłem ClassBoard z ClassMove dodałem repaint na końcu KeyPressed i jeszcze jakieś małe poprawki żeby program wystartował.

/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package javaswingsokoban;


import java.awt.Color;

import java.awt.Graphics;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import javax.swing.JComponent;

import javax.swing.JPanel;


/**

 *

 * @author marcin

 */

public class ClassBoard extends JComponent implements KeyListener{


  // ClassMove classMove = new ClassMove();

    private int sizeSquare = 40;

    private int positionX = 50;

    private int positionY = 50;


    //0 - mur czarny

    //1 - puste pole bialy

    //2 - pudelko zielony

    //3 - ludzik czerwony

     int[][] plansza = {

        {0,0,0,0,0,0,0,0,0,0,0,0,1,1},

        {0,1,1,1,1,0,1,1,1,1,1,0,0,0},

        {0,1,1,1,1,0,1,2,1,1,2,1,1,0},

        {0,1,1,1,1,0,2,0,0,0,0,1,1,0},

        {0,1,1,1,1,1,1,1,1,0,0,1,1,0},

        {0,3,1,1,1,0,1,0,1,1,2,1,0,0},

        {0,0,0,0,0,0,1,0,0,2,1,2,1,0},

        {1,1,0,1,2,1,1,2,1,2,1,2,1,0},

        {1,1,0,1,1,1,1,0,1,1,1,1,1,0},

        {1,1,0,0,0,0,0,0,0,0,0,0,0,0}

    };


    public ClassBoard() {

        this.setFocusable(true);

        addKeyListener(this);

    }


    @Override

    public void paint(Graphics graphics){

        drawBoard(graphics);

    }


    void drawBoard(Graphics graphics){

        super.paint(graphics);

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

            for(int j = 0; j < plansza[0].length; ++j){

                if(plansza[i][j] == 0){

                    graphics.setColor(Color.BLACK);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);

                } else if(plansza[i][j] == 1){

                    graphics.setColor(Color.WHITE);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);

                } else if(plansza[i][j] == 2){

                    graphics.setColor(Color.GREEN);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);

                } else if(plansza[i][j] == 3){

                    graphics.setColor(Color.RED);

                    graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare, sizeSquare);                    

                }

            }

        }

    }


      private int x = 5;

    private int y = 1;


    @Override

    public void keyTyped(KeyEvent e) {

    }


    @Override

    public void keyPressed(KeyEvent keyEvent) {

        switch(keyEvent.getKeyCode()){

            case KeyEvent.VK_UP:

                if(plansza[x - 1][y] == 1){

                    plansza[x - 1][y] = 3;

                    plansza[x][y] = 1;

                    x--;

                }

                System.out.println("wcisles up");

                break;

            case KeyEvent.VK_DOWN:

                System.out.println("wcisles down");

                if(plansza[x + 1][y] == 1){

                    plansza[x + 1][y] = 3;

                    plansza[x][y] = 1;

                    x++;

                }

                break;

            case KeyEvent.VK_LEFT:

                System.out.println("wcisles left");

                if(plansza[x][y - 1] == 1){

                    plansza[x][y - 1] = 3;

                    plansza[x][y] = 1;

                    y--;

                }

                break;

            case KeyEvent.VK_RIGHT:

                System.out.println("wcisles right");

                if(plansza[x][y + 1] == 1){

                    plansza[x][y + 1] = 3;

                    plansza[x][y] = 1;

                    y++;

                }

                break;

        }

        repaint();

    }


    @Override

    public void keyReleased(KeyEvent e) {

    }


}

Według mnie kod nie wygląda najgorzej, jedynie tekst “wcisnales up” niemiłosiernie mnie irytuje masz tu 3 błędy,

  1. słowo nie istnieje w języku polskim, (a jak założymy że jest to słowo polskie to)

  2. brak polskich znaków,

3 mieszanie polskiego i angielskiego słownictwa.

i ewentualnie użyj enumeratora zamiast nic nie znaczących 0,1,2,3.

Nie do końca rozumiem w czym jest problem. Masz klasę ClassMove, która reaguje na wciśnięcie klawisza odpowiedzialnego za poruszanie, więc właściwie wszystko masz gotowe. Wystarczy dołożyć odświeżenie panelu pod koniec metody keyPressed.

Odświeżanie za pomocą timera to zły pomysł, co zresztą sam zauważyłeś.

Zgadzam się z przedmówcą, ale pamiętaj, aby odświeżanie miało miejsce nie dla wszystkich klawiszy (kolega grzelix zapewne się zagapił), a tylko dla tych przez Ciebie wybranych.

  1. program podzieliłem celowo na 3 klasy;

  2. słowa typu “wcisnales up” celowo wstawiłem dla sprawdzenia czy działa implementacja klawiatury i przepraszam za mieszanie dwóch języków;

  3. mój problem tkwi właśnie z odświeżaniem JPanel, utworzyłem w klasie statyczny obiekt JFrame i dodałem za pomocą metody add(), później w klasie ClassMove na końcu metody KeyPresed() odwołałem się do tego statycznego obiektu ClassBoard.jPanel.repaint(); i użyłem metodę repaint(). lecz to niestety nie działa i to mój problem

Dodane 09.08.2012 (Cz) 20:15

nie rozumiem po co wstawiłeś ten link, nie będę używać wątków w tym programie.

dziękuje ale chce skończyć ten program w sposób w który zacząłem robić, mój problem to metoda odświeżająca jPanel, nie wiem jak użyć repaint lub revalidate.

Wywołaj metodę repaint() nie na JFrame, tylko na ClassBoard (który jest JPanelem).

A tak poza tym, to używanie statycznych pól do interakcji między komponentami jest złym pomysłem - bo co jeśli stworzysz 20 paneli? Dodasz 20 pól statycznych? A może listę? Zamiast tego powinieneś obiektowi klasy ClassMove przekazać referencję do stworzonego obiektu klasy ClassBoard, żeby przy każdym wciśnięciu klawisza wywoływać na nim repaint().

Tym SwingWorkerem się nie przejmuj, autor posta chyba sam nie wiedział co pisze (i po co).

niewiem czy dobrze rozumiem, powinienem utworzyć metode

public void refresh(){

        repaint();

    }

w klasie ClassBoard i później klasie ClassMove na końcu metody keyPressed() utworzyć referencje do klasy ClassBoard i wywołać utworzoną metodę refresh()??

Najprościej będzie tak:

/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package javaswingsokoban;


import java.awt.Color;

import java.awt.Graphics;

import javax.swing.JPanel;


/**

 * @author marcin

 */

public class ClassBoard extends JPanel {


	private static final long serialVersionUID = 1473893977567134451L;


	private ClassMove classMove = new ClassMove(this);

	private int sizeSquare = 40;

	private int positionX = 50;

	private int positionY = 50;


	// 0 - mur czarny

	// 1 - puste pole bialy

	// 2 - pudelko zielony

	// 3 - ludzik czerwony

	public int[][] plansza = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 },

			{ 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0 }, { 0, 1, 1, 1, 1, 0, 1, 2, 1, 1, 2, 1, 1, 0 },

			{ 0, 1, 1, 1, 1, 0, 2, 0, 0, 0, 0, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0 },

			{ 0, 3, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 2, 1, 0 },

			{ 1, 1, 0, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 0 }, { 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0 },

			{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };


	public ClassBoard() {

		this.setFocusable(true);

		addKeyListener(classMove);

	}


	@Override

	public void paint(Graphics graphics) {

		drawBoard(graphics);

	}


	void drawBoard(Graphics graphics) {

		super.paint(graphics);

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

			for (int j = 0; j < plansza[0].length; ++j) {

				if (plansza[i][j] == 0) {

					graphics.setColor(Color.BLACK);

					graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare,

							sizeSquare);

				} else if (plansza[i][j] == 1) {

					graphics.setColor(Color.WHITE);

					graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare,

							sizeSquare);

				} else if (plansza[i][j] == 2) {

					graphics.setColor(Color.GREEN);

					graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare,

							sizeSquare);

				} else if (plansza[i][j] == 3) {

					graphics.setColor(Color.RED);

					graphics.fillRect((sizeSquare * j) + positionX, (sizeSquare * i) + positionY, sizeSquare,

							sizeSquare);

				}

			}

		}

	}

}

/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package javaswingsokoban;


import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;


/**

 * @author marcin

 */

public class ClassMove implements KeyListener {


	private int x = 5;

	private int y = 1;

	private ClassBoard classBoard;


	public ClassMove(ClassBoard classBoard) {

		this.classBoard = classBoard;

	}


	@Override

	public void keyTyped(KeyEvent e) {

	}


	@Override

	public void keyPressed(KeyEvent keyEvent) {

		switch (keyEvent.getKeyCode()) {

		case KeyEvent.VK_UP:

			if (classBoard.plansza[x - 1][y] == 1) {

				classBoard.plansza[x - 1][y] = 3;

				classBoard.plansza[x][y] = 1;

				x--;

			}

			System.out.println("wcisles up");

			break;

		case KeyEvent.VK_DOWN:

			System.out.println("wcisles down");

			if (classBoard.plansza[x + 1][y] == 1) {

				classBoard.plansza[x + 1][y] = 3;

				classBoard.plansza[x][y] = 1;

				x++;

			}

			break;

		case KeyEvent.VK_LEFT:

			System.out.println("wcisles left");

			if (classBoard.plansza[x][y - 1] == 1) {

				classBoard.plansza[x][y - 1] = 3;

				classBoard.plansza[x][y] = 1;

				y--;

			}

			break;

		case KeyEvent.VK_RIGHT:

			System.out.println("wcisles right");

			if (classBoard.plansza[x][y + 1] == 1) {

				classBoard.plansza[x][y + 1] = 3;

				classBoard.plansza[x][y] = 1;

				y++;

			}

			break;

		}

		classBoard.repaint();

	}


	@Override

	public void keyReleased(KeyEvent e) {

	}

}

nie pomyślałem o takim zapisie, działa i dziękuje ;), po co użyłeś zmiennej do deserializacji?? jeszcze raz dziękuje za pomoc.

A tak z przyzwyczajenia, żeby nie było warninga bo mnie wkurza żółta ikonka w Eclipse. Możesz to oczywiście wywalić :slight_smile:

używam Netbeans-a, usunąłem tą zmienną i nie było warninga. muszę dokończyć grę, brakuje jeszcze warunków odpowiedzialnych za poruszanie kwadratami po planszy i sprawdzanie czy ustawiono wszystkie.