IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AWT/Swing Java Discussion :

Thread pour une animation dans un JPanel


Sujet :

AWT/Swing Java

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    406
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 406
    Points : 279
    Points
    279
    Par défaut Thread pour une animation dans un JPanel
    Salut tout le monde,
    J'ai le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Timer;
    import java.util.TimerTask;
    import javax.imageio.ImageIO;
    import javax.swing.JPanel;
    
    public class PanelAnimation extends JPanel {
        // Un tableau d'images
        private BufferedImage[] tableauImages = null;
    
        // Un nombre d'images
        public static final int NOMBRE_IMAGES = 7;
    
        // L'image en cours
        private BufferedImage imageEnCours = null;
    
        // Le Timer pour l'animation
        private Timer minuteur = null;
    
        // La tâche du minuteur
        private TimerTask tache = null;
    
        public PanelAnimation() {
            // On associe un layout
            this.setLayout(new BorderLayout());
    
            // On associe une taille au panelAnimation
            this.setPreferredSize(new Dimension(200, 200));
    
            // On déclare le tableau d'images (7 images)
            tableauImages = new BufferedImage[NOMBRE_IMAGES];
    
            // On charge les images
            chargeImages();
    
            // On instancie l'image en cours par défaut
            imageEnCours = tableauImages[0];
    
            // On instancie un minuteur pour l'animation
            minuteur = new Timer();
    
            // On définit une tâche pour le minuteur
            tache = new TimerTask() {
                // On lance l'animation dans un nouveau Thread
                @Override
                public void run() {
                    // On lance l'animation
                    lanceAnimation();
                }
            };
    
            // On définit l'emploi du temps du minuteur :
            // - suivre la tâche lanceAnimation()
            // - à partir de maintenant
            // - toutes les 50ms
            minuteur.schedule(tache, 0, 50);
        }
    
        public void chargeImages() {
            // Pour toutes les images
            for (int i = 0; i < NOMBRE_IMAGES; i++) {
                try {
                    // On charge l'image
                    tableauImages[i] = ImageIO.read(new File("./src/fr/" +
                            "apreslaclasse/alcgged/images/" + i + ".jpg"));
    
                } catch (IOException exception) {
                    // On affiche la pile d'appel
                    exception.printStackTrace();
    
                    // On affiche un message
                    System.out.println("L'image " + i + ".jpg " +
                            "n'a pas été lue");
    
                } catch (IllegalArgumentException exception) {
                    // On affiche la pile d'appel
                    exception.printStackTrace();
    
                    // On affiche un message
                    System.out.println("Le fichier image " + i + ".jpg " +
                            "est null");
    
                } catch (NullPointerException exception) {
                    // On affiche la pile d'appel
                    exception.printStackTrace();
    
                    // On affiche un message
                    System.out.println("L'image " + i + ".jpg " +
                            "n'a pas été trouvée");
                }
            }
        }
    
        public void lanceAnimation() {
            // TODO: Faire ça dans une boucle
            // Si l'image en cours est la première image
            if (imageEnCours.equals(tableauImages[0])) {
                // On change l'image en cours
                imageEnCours = tableauImages[1];
    
                // On affiche l'image
                this.repaint();
    
            // Si l'image en cours est la seconde image
            } else if (imageEnCours.equals(tableauImages[1])) {
                // On change l'image en cours
                imageEnCours = tableauImages[2];
    
                // On affiche l'image
                this.repaint();
    
            // Si l'image en cours est la troisième image
            } else if (imageEnCours.equals(tableauImages[2])) {
                // On change l'image en cours
                imageEnCours = tableauImages[3];
    
                // On affiche l'image
                this.repaint();
    
            // Si l'image en cours est la quatrième image
            } else if (imageEnCours.equals(tableauImages[3])) {
                // On change l'image en cours
                imageEnCours = tableauImages[4];
    
                // On affiche l'image
                this.repaint();
    
            // Si l'image en cours est la cinquième image
            } else if (imageEnCours.equals(tableauImages[4])) {
                // On change l'image en cours
                imageEnCours = tableauImages[5];
    
                // On affiche l'image
                this.repaint();
    
            // Si l'image en cours est la sixième image
            } else if (imageEnCours.equals(tableauImages[5])) {
                // On change l'image en cours
                imageEnCours = tableauImages[6];
    
                // On affiche l'image
                this.repaint();
    
            // Si l'image en cours est la septième image
            } else if (imageEnCours.equals(tableauImages[6])) {
                // On change l'image en cours
                imageEnCours = tableauImages[0];
    
                // On affiche l'image
                this.repaint();
    
                // ICI : tache.cancel();
            } 
        }
    
        @Override
        public void paintComponent(Graphics g) {
            // On affiche l'image en cours dans le panel
            g.drawImage(imageEnCours, 0, 0, this);
        }
    }
    J'ai une animation dans un JPanel. J'utilise un Timer.
    A partir du Thread du TimerTask, je lance une méthode (lanceAnimation()).
    Quand j'exécute mon code comme cela, je vois bien l'animation qui fait des tours et des tours de boucle. Mais du coup, le Thread ne s'arrête plus ! A un moment, plus tard dans le code, je ferme la fenêtre qui gère ce JPanel (avec dispose()) mais le Thread continue encore de tourner ! Pourquoi ?
    Sinon, si je mets le code suivant : tache.cancel(); au commentaire rouge (voir plus haut dans mon code), l'animation fait un tour et s'arrête, le Thread a l'air également de s'arrêter. Cependant, c'est comme si le Thread lançait l'animation à partir de la méthode lanceAnimation() 7 fois (autant que le nombre d'images)... Bizarre, non ?

  2. #2
    Membre expérimenté
    Avatar de visiwi
    Profil pro
    Inscrit en
    Février 2008
    Messages
    1 050
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 1 050
    Points : 1 340
    Points
    1 340
    Par défaut
    Citation Envoyé par womannosky Voir le message
    Cependant, c'est comme si le Thread lançait l'animation à partir de la méthode lanceAnimation() 7 fois (autant que le nombre d'images)...
    N'est-ce pas plutôt parce que ton animation possède 7 images et que tu la stop à la fin de la 7ème ? Sûrement...

    Si ton thread continue alors que ta fenêtre est fermé, c'est que je pense, ton appli, elle, n'est pas terminé. Lorsque tu ferme ta fenêtre cela doit appeler un :
    Ta méthode lanceAnimation() peut-être largement plus concise, en gérant seulement un incrément bouclé sur le nombre d'images :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
     
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Timer;
    import java.util.TimerTask;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
     
    public class PanelAnimation extends JPanel {
     
    	public static void main(final String[] args) {
    		JFrame f = new JFrame();
    		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		f.setContentPane(new PanelAnimation());
    		f.pack();
    		f.setVisible(true);
    	}
        // Un tableau d'images
        private BufferedImage[] tableauImages = null;
     
        // Un nombre d'images
        public static final int NOMBRE_IMAGES = 7;
     
        // L'image en cours
        private int imageEnCours = 0;
     
        // Le Timer pour l'animation
        private Timer minuteur = null;
     
        // La tâche du minuteur
        private static TimerTask tache = null;
     
        public PanelAnimation() {
            // On associe un layout
            this.setLayout(new BorderLayout());
     
            // On associe une taille au panelAnimation
            this.setPreferredSize(new Dimension(200, 200));
     
            // On déclare le tableau d'images (7 images)
            tableauImages = new BufferedImage[NOMBRE_IMAGES];
     
            // On charge les images
            chargeImages();
     
            // On instancie un minuteur pour l'animation
            minuteur = new Timer();
     
            // On définit une tâche pour le minuteur
            tache = new TimerTask() {
                // On lance l'animation dans un nouveau Thread
                @Override
                public void run() {
                    // On lance l'animation
                    lanceAnimation();
                }
            };
     
            // On définit l'emploi du temps du minuteur :
            // - suivre la tâche lanceAnimation()
            // - à partir de maintenant
            // - toutes les 50ms
            minuteur.schedule(tache, 0, 200);
        }
     
        public void chargeImages() {
            // Pour toutes les images
            for (int i = 0; i < NOMBRE_IMAGES; i++) {
                try {
                    // On charge l'image
                    tableauImages[i] = ImageIO.read(new File("a" +
                            i + ".png"));
     
                } catch (IOException exception) {
                    // On affiche la pile d'appel
                    exception.printStackTrace();
     
                    // On affiche un message
                    System.out.println("L'image " + i + ".jpg " +
                            "n'a pas été lue");
     
                } catch (IllegalArgumentException exception) {
                    // On affiche la pile d'appel
                    exception.printStackTrace();
     
                    // On affiche un message
                    System.out.println("Le fichier image " + i + ".jpg " +
                            "est null");
     
                } catch (NullPointerException exception) {
                    // On affiche la pile d'appel
                    exception.printStackTrace();
     
                    // On affiche un message
                    System.out.println("L'image " + i + ".jpg " +
                            "n'a pas été trouvée");
                }
            }
        }
     
        public void lanceAnimation() {
        	System.out.println("animation...");
        	imageEnCours++;
        	if (imageEnCours >= NOMBRE_IMAGES) {
        		imageEnCours = 0;
        	}
        	repaint();    	
        }
     
        @Override
        public void paintComponent(Graphics g) {
            // On affiche l'image en cours dans le panel
            g.drawImage(tableauImages[imageEnCours], 0, 0, this);
        }
    }
    Attention, j'ai modifié le nom des fichiers...

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    406
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 406
    Points : 279
    Points
    279
    Par défaut
    Citation Envoyé par visiwi Voir le message
    Si ton thread continue alors que ta fenêtre est fermé, c'est que je pense, ton appli, elle, n'est pas terminé. Lorsque tu ferme ta fenêtre cela doit appeler un :
    Ta méthode lanceAnimation() peut-être largement plus concise, en gérant seulement un incrément bouclé sur le nombre d'images :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
        public void lanceAnimation() {
        	System.out.println("animation...");
        	imageEnCours++;
        	if (imageEnCours >= NOMBRE_IMAGES) {
        		imageEnCours = 0;
        	}
        	repaint();    	
        }
     
        @Override
        public void paintComponent(Graphics g) {
            // On affiche l'image en cours dans le panel
            g.drawImage(tableauImages[imageEnCours], 0, 0, this);
        }
    }
    Salut !
    Pour ce qui est du tache.cancel(), en effet, mon application n'est pas terminée. Mais tu penses que lorsque je ferme la fenêtre (où se trouve mon panel avec l'animation), un tache.cancel() est appelé automatiquement ? ou c'est à moi de l'appeler pour terminer le Thread ?

    Sinon, j'ai beau essayer de réduire le code se trouvant dans lanceAnimation() mais rien ne marche (sûrement à cause d'une subtilité que je ne comprend pas dans le Thread). Une simple boucle for() ne marche pas... Sinon, le code que tu m'as fourni ne fonctionne pas car tu incrémentes imageEnCours (qui est une BufferedImage donc non incrémentable).

    Sinon, une autre chose que je ne comprend pas, c'est que le Thread lance l'animation en continue alors qu'il devrait la lancer une fois, je n'appelle qu'une seule fois la méthode lanceAnimation() dans le thread...

  4. #4
    Membre expérimenté
    Avatar de visiwi
    Profil pro
    Inscrit en
    Février 2008
    Messages
    1 050
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 1 050
    Points : 1 340
    Points
    1 340
    Par défaut
    Citation Envoyé par womannosky Voir le message
    Sinon, le code que tu m'as fourni ne fonctionne pas car tu incrémentes imageEnCours (qui est une BufferedImage donc non incrémentable).
    imageEnCours est un int dans mon exemple, c'est une BufferedImage dans le tien.

    Mais tu penses que lorsque je ferme la fenêtre (où se trouve mon panel avec l'animation), un tache.cancel() est appelé automatiquement ? ou c'est à moi de l'appeler pour terminer le Thread ?
    tache.cancel() n'est probablement jamais appelée automatiquement, mais le fait de terminer une appliccation (pas nécessairement une fenêtre) implique que le Thead sera tué. Si l'application tourne encore, le Thread continuera de s'exécuter tant que rien ne le contrarie.
    C'est donc à toi de lui dire que son travail est terminé.

    Sinon, une autre chose que je ne comprend pas, c'est que le Thread lance l'animation en continue alors qu'il devrait la lancer une fois, je n'appelle qu'une seule fois la méthode lanceAnimation() dans le thread...
    Tu créer un Timer, sont rôle est d'appeler lanceAnimation() régulièrement, toute les 200ms dans ton programme. Tu n'a écris qu'une fois l'appel à lanceAnimation() mais le Timer l'appel régulièrement.

  5. #5
    Membre actif
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    406
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 406
    Points : 279
    Points
    279
    Par défaut
    Citation Envoyé par visiwi Voir le message
    imageEnCours est un int dans mon exemple, c'est une BufferedImage dans le tien.
    Ok ok, je n'avais pas vu, je vais corriger ça dans mon programme.


    Citation Envoyé par visiwi Voir le message
    tache.cancel() n'est probablement jamais appelée automatiquement, mais le fait de terminer une appliccation (pas nécessairement une fenêtre) implique que le Thead sera tué. Si l'application tourne encore, le Thread continuera de s'exécuter tant que rien ne le contrarie.
    C'est donc à toi de lui dire que son travail est terminé.
    Ok, mon soucis est que si jamais mon programme effectue une tache qui ne se termine pas, comme le Thread de l'animation n'est pas tué, si l'utilisateur choisit de fermer l'application à ce moment là (en cliquant sur la croix rouge de ma JDialog => ma fenêtre d'attente), le programme plante et ne se termine pas... J'ai regardé, normalement, aucune tâche n'est programmée pour une durée indéterminée, donc ça ira.


    Citation Envoyé par visiwi Voir le message
    Tu créer un Timer, sont rôle est d'appeler lanceAnimation() régulièrement, toute les 200ms dans ton programme. Tu n'a écris qu'une fois l'appel à lanceAnimation() mais le Timer l'appel régulièrement.
    Oui, en effet, je suis bête...

    Merci à toi pour toutes ces bonnes réponses !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. animer le mouvement d'une bille dans un JPanel
    Par berry dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 07/05/2006, 00h28
  2. Conseils pour une reconversion dans l'informatique
    Par Laurentq1970 dans le forum Etudes
    Réponses: 11
    Dernier message: 02/06/2005, 22h16
  3. Importance des accents pour une recherche dans postgre
    Par glouf dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 05/03/2005, 13h25
  4. Réponses: 6
    Dernier message: 14/12/2004, 02h47
  5. Réponses: 4
    Dernier message: 18/04/2004, 13h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo