1


0

Que se passe-t-il avec JPanel en Java? Qu’est-ce que je fais mal?

J’ai un problème avec mon JPanel. Je lui dis de repeindre () à la fin du constructeur, puis j’ai une animation (un sprite se déplaçant sur l’écran), mais le JPanel ne se peint pas tant que le sprite n’a pas traversé son animation et atteint son nouveau point sur le écran. J’ai collé mon code ci-dessous. Je n’ai jamais utilisé de JPanel pour des graphiques personnalisés auparavant. Qu’est-ce que je fais mal?

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

class Battle extends JPanel implements KeyListener {

    AllyParty ap;
    boolean showMenu = false;
    BufferedImage image;
    EnemyParty ep;
    Graphics screen;
    Image allyPic[], enemyPic[];
    int enemyCount;
    int mtCount = 0;
    int turn[];
    MediaTracker mt;
    Random rand;

    public Battle(AllyParty allyparty) {

        /*Initial JPanel subclass setup*/
        setSize(800, 600);
        setBackground(Color.black);

        /*Create our ally party*/
        ap = new AllyParty();
        ap = allyparty;
        ap.setCallingObject(this);

        /*Create randomizer and random number variable*/
        long seed = System.currentTimeMillis();
        rand = new Random(seed);

        /*Use rand to select a number of enemies*/
        enemyCount = rand.nextInt(12) + 1;

        enemyCount = 12; //TEMP
        ep = new EnemyParty(enemyCount);


        /*Create the individual enemies in ep and place them*/
        for (int i = 0; i < enemyCount; i++) {
            ep.enemy[i] = new Enemy(1);
        }

        ep.setCallingObject(this);

        /*Initialize images and set them to their starting values*/
        allyPic = new Image[4];
        enemyPic = new Image[enemyCount];

        /* for (int i = 0; i < 4; i++)
        {
        ap.ally[i].setCurrentImage(Ally.STAND)
        allyPic[i] = ap.ally[i].getCurrentImage();
        }

        for (int i = 0; i < enemyCount; i++)
        {
        enemyPic[i] = ep.enemy[i].getImage();
         */
        /*Set battle placement*/
        ap.setPos(0);
        ep.setPos(0);

        //Create the Buffered Image
        image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

        //Set up the Media Tracker
        mt = new MediaTracker(this);
        for (int i = 0; i < 4; i++) {
            mt.addImage(allyPic[i], mtCount++);
        }

        for (int i = 0; i < ep.getEnemyCount(); i++) {
            mt.addImage(enemyPic[i], mtCount++);
        }

        mt.addImage(image, mtCount++);

        try {
            mt.waitForAll();
        } catch (Exception e) {
        }

        /*Temporary Section*/
        findTurns();

        repaint();
        // ap.ally[0].advance();
        advance();
    }

    public void findTurns() {
        int total = ep.getEnemyCount() + 4; //Enemies + allies

        int used[] = new int[total];
        turn = new int[total];

        int next = rand.nextInt(total);

        for (int j = 0; j < total; j++) {
            used[j] = -1;
        }

        for (int j = 0; j < total; j++) {
            for (int k = 0; k < j; k++) {
                if (used[k] == next) {
                    k = -1;
                    next = rand.nextInt(total);
                }
            }
            turn[j] = next;
            used[j] = next;
        }
    }

    public void advance() {
        while (ap.ally[0].getXPos() > 350) {
            ap.ally[0].moveLeft(20);
            ap.ally[0].setCurrentImage(Ally.WALK);
            repaint();
            try {
                Thread.sleep(200);
            } catch (Exception e) {
            }
            ap.ally[0].setCurrentImage(Ally.STAND);
            repaint();
            try {
                Thread.sleep(200);
            } catch (Exception e) {
            }
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        screen = image.getGraphics();

        for (int i = 0; i < 4; i++) {
            allyPic[i] = ap.ally[i].getCurrentImage();
        }

        for (int i = 0; i < ep.getEnemyCount(); i++) {
            enemyPic[i] = ep.enemy[i].getCurrentImage();
        }

        for (int i = 0; i < 4; i++) {
            screen.drawImage(allyPic[i], ap.ally[i].getXPos(),
                ap.ally[i].getYPos(), this);
        }

        for (int i = 0; i < enemyCount; i++) {
            screen.drawImage(enemyPic[i], ep.enemy[i].getXPos(),
                ep.enemy[i].getYPos(), 100, 75, this);
        }

        g.drawImage(image, 0, 0, this);
    }

    public void keyPressed(KeyEvent k) {}
    public void keyReleased(KeyEvent k) {}
    public void keyTyped(KeyEvent k) {}
}

3 Answer


6


What am I doing wrong?

{vide} 1) utilisez KeyBindings au lieu de http://docs.oracle.com/javase/tutorial/uiswing/events/ keylistener.html [KeyListener]

{vide} 2) n’utilisez jamais Thread.sleep (int) pendant EDT, car http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html}freeze Swing GUI Swing]

{vide} 3) pour les animations / retarder l’événement, utilisez Swing Timer

{vide} 4) vous pouvez utiliser Icon dans le http://docs.oracle.com/javase/tutorial/uiswing/ components / label.html [JLabel] pour afficher BufferedImage dans le JPanel


4


Selon toute vraisemblance, vous modifiez votre "modèle" (la position de votre sprite) dans l’AWT-Thread. Les repeints sont des événements distribués dans AWT-EventThread. Par conséquent, vous empêchez AWT de repeindre votre panneau tant que vos opérations sont exécutées à l’intérieur de l’AWT-Thread.

Deux options:

{vide} 1) Déplacez vos "opérations / modèle" en dehors du thread AWT (dans un autre thread)

{vide} 2) Relâchez le fil AWT de temps en temps, permettant aux événements de repeindre d’être effectués (pour moi, ce n’est pas une bonne option)

Assurez-vous que si vous partagez des variables entre deux threads, vous utilisez «volatile» ou «synchronisé» (selon la façon dont vous travaillez, on devrait mieux répondre à vos besoins)


0


Pour autant que je sache, votre problème est que vous appelez advance () dans le constructeur. Votre code ressemble probablement à quelque chose comme ceci:

JFrame frame = new JFrame();
frame.add(new Battle());
frame.setVisible(true);

Voici ce qui se passe:

  1. un nouveau JFrame est créé

  2. une nouvelle bataille est créée

  3. à la fin du constructeur Battle repaint () est appelé

  4. alors advance () est appelé

  5. Advance () appelle elle-même la repeinture plusieurs fois

  6. Advance () renvoie

  7. le constructeur retourne

  8. la bataille est ajoutée au cadre

  9. le cadre est rendu visible

  10. la bataille est peinte

Pour résoudre votre problème, vous devez supprimer l’appel à advance () dans le constructeur et l’appeler une fois que votre cadre est affiché.