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 :

Problème animation avec PaintComponent [Débutant(e)]


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Octobre 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 19
    Par défaut Problème animation avec PaintComponent
    Salut à tous,

    Je débute en JAVA et essaye de faire des choses basiques avec Swing.
    Je cherche à réaliser une animation sur un JPanel (un cercle qui se déplace en utilisant une boucle et la méthode repaint() pour chaque itération).
    Bref exercice classique, mais rien ne se déplace chez moi

    En gros j'ai deux classes :
    une classe Fenetre ou je définis ma fenetre, taille etc
    qui contient ma méthode main() et une méthode go() pour lancer l'animation.

    une classe Panneau qui étend JPanel où je redéfinis la méthode PaintComponent(Graphics g)

    Voici mes classes
    ma classe Fenetre : http://pastebin.com/vgQFfHV7
    ma classe Panneau : http://pastebin.com/m44CLMYn

    Le problème vient des getters et setters dans la méthode go() :

    quand je fais ça, ça marche :
    Nom : javaMARCHE.png
Affichages : 1138
Taille : 6,1 Ko
    Mais là, ça marche plus et je comprends pas pourquoi :
    Nom : java.png
Affichages : 1350
Taille : 6,5 Ko

    Merci

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    N'oublie pas que Java est sensible à la casse. GetX() et getX() ne sont pas les mêmes méthodes (au sujet du code, il est préférable que tu montres ton code en texte dans le message, avec les balises CODE (bouton #), c'est beaucoup plus pratique pour tous, que cela soit par rapport à du pastebin, mais encore plus pour des copies d'écran). Les méthodes getX() et getY() sont des méthodes existantes de JPanel qui donnent les coordonnées du JPanel dans son conteneur parent, coordonnées vallant toujours (0,0) dans cette configuration.

    La confusion entre GetX() et getX() est aisée. Les conventions Java recommandent de nommer les méthodes en lowerCamelCase, donc le nom doit commencer par une minuscule. Mais si tu suivais la convention, tu redéfinirais les méthodes getX() et getY() de JPanel et tu leur donnerais un sens incorrect, ce qui donnerait des comportements erratiques à ton UI. Il vaudrait mieux nommer tes méthodes avec un sens plus précis, ce qui t'éviterait à l'avenir de telles confusions.
    Du style, par exemple :
    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
    public class Panneau extends JPanel {
     
        private int x;
        private int y;
     
        public int getOvalX() {
            return x;
        }
     
        public int getOvalY() {
            return y;
        }
     
        public void setOvalX(int x) {
            this.x = x;
        }
     
        public void setOvalY(int y) {
            this.y = y;
        }
     
        public void paintComponent(Graphics g) {
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, getWidth(), getHeight());
     
            g.setColor(Color.GREEN);
            g.fillOval(x, y, 30, 30);
        }
    }
    Aussi, il est préférable de laisser Swing faire ce qu'il fait, plutôt que de chercher à le refaire à sa place, ce qu'on ne fera pas forcément de la manière la plus optimisée, ou bien on pourra passer à côté d'un fonctionnement qu'on ignore et qui peut donner des comportements erratiques de l'UI. Je veux parler du fait que tu remplisses le composant de noir, plutôt que de laisser Swing dessiner le fond du composant en noir :
    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
    public class Panneau extends JPanel {
     
        private int x;
        private int y;
     
        public Panneau() {
            setBackGround(Color.BLACK);
        }
     
        public int getOvalX() {
            return x;
        }
     
        public int getOvalY() {
            return y;
        }
     
        public void setOvalX(int x) {
            this.x = x;
        }
     
        public void setOvalY(int y) {
            this.y = y;
        }
     
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
     
            g.setColor(Color.GREEN);
            g.fillOval(x, y, 30, 30);
        }
    }
    Voire même ne pas forcer le fond en noir dans le constructeur et laisser le code appelant le faire, ce qui permet de choisir une couleur facilement sans modifier la classe. D'ailleurs, pour le vert du disque tu pourrais utiliser setForeGround()/getForeGround() de façon à pouvoir réutiliser ton Panneau en choisissant différentes couleurs sans changer le code de la classe.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Octobre 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 19
    Par défaut
    Merci Joel,
    en effet je n'avais pas fait attention à ce Get et get, et donc je n'appelais pas la methode souhaitée

  4. #4
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Octobre 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 19
    Par défaut
    OK cette fois ci j'ai utilisée une classe interne pour changer, donc plus besoin de passer par des getters :

    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
    public class test {
     
        private int x;
        Panneau pano;
        JFrame cadre;
     
        public test() {
            //Je créé ma fenetre et y ajoute mon Panneau dedans
            JFrame cadre = new JFrame();
            pano = new Panneau();
            cadre.getContentPane().add(pano);
            cadre.setSize(300, 300);
            cadre.setVisible(true);
            cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
     
        public void go() throws InterruptedException {
            for (int i = 0; i < 180; i++) {
                x++;
                Thread.sleep(10);
                pano.repaint();
            }
        }
     
        class Panneau extends JPanel {
     
            public void paintComponent(Graphics g) {
                        g.setColor(Color.BLACK);
                        g.fillRect(0, 0, getWidth(), getHeight());
                        g.setColor(Color.PINK);
                        g.fillOval(x, 0, 20, 20);                  
                }
        }
     
        public static void main(String[] args) throws InterruptedException {
                new test().go();
        }
    }
    ca marche bien, cool. Mon cercle se déplace de l'origine à une coordonnée fixé en utilisant une boucle avec appel de la méthode repaint().

    Cette fois ci je voudrais que mon cercle se déplace en ligne droite mais sans jamais s'arreter cette fois, quand il arrive sur le rebord de mon panneau, il rebondit et part en sens inverse.

    Par contre j'ai pas trop d'idées comment faire. J'avais pensé à :
    vu que ca s'arrete jamais, remplacer une boucle for par while(true). Et aussi déplacer le thread.sleep de la méthode go() et directement l'injecter dans la méthode paintComponent(Graphics g). Mais là ca ne fonctionne plus au niveau du thread. Le thread.sleep est bien utilisé : pendant l'éxécution la fenetre est toute grise pendant la durée de l'argument du sleep et apres on voit directement le résultat final. Le déroulé de l'animation n'apparait pas.

  5. #5
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Le plus simple pour gérer ce genre de choses est de passer par un Timer plutôt que par une boucle dans un thread. Ensuite, avec 2 variables correspondant à un déplacement horizontal et vertical, tu fais varier les coordonnées. Il te suffit donc de donner la valeur que tu veux à ces variables de déplacement : 0 correspond à aucun déplacement (sur un axe), un entier positif à un déplacement dans un sens, un négatif à un déplacement dans l'autre, la valeur absolue étant la vitesse. Arrivé au bord, tu inverses la valeur de déplacement (attention à prendre en compte les dimensions du mobile).
    La même technique est applicable pour une animation liée à une interaction (touches du clavier par exemple)

    Illustration exemple :
    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
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.FlowLayout;
    import java.awt.Graphics;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.KeyboardFocusManager;
    import java.awt.event.KeyEvent;
     
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JSpinner;
    import javax.swing.SpinnerNumberModel;
    import javax.swing.Timer;
    import javax.swing.plaf.basic.BasicArrowButton;
     
    public class AnimationDemo extends JPanel {
     
    	private static final long serialVersionUID = 1L;
     
    	private static final int WIDTH = 30;
    	private static final int HEIGHT = WIDTH;
     
    	private int x; // abscisse du mobile
    	private int y; // ordonnée du mobile
     
    	private int dx; // sens de déplacement du mobile sur l'axe horizontal
    	private int dy; // sens de déplacement du mobile sur l'axe vertical
     
    	private int v=1; // vitesse de déplacement (en pixel/frame)
     
    	private Timer timer = new Timer(33, e->animate()); // timer pour l'animation (toutes les 33 ms, donc 30 images par secondes) : on appelle donc la méthode animate() toutes les 33 ms
     
    	public void setVitesse(int v) {
    		this.v=Math.min(8, Math.max(1, v)); // on borne la vittesse : 1<=v<=8
    	}
     
    	public void setDeplacement(int dx, int dy) {
    		this.dx=(int)Math.signum(dx); // on prend le signe pour que dx soit soit -1, soit 0, soit 1
    		this.dy=(int)Math.signum(dy); 
    	}
     
    	public void setDeplacementX(int dx) {
    		this.dx=(int)Math.signum(dx);
    	}
     
    	public void setDeplacementY(int dy) {
    		this.dy=(int)Math.signum(dy);
    	}
     
    	public boolean isAnimated() {
    		return timer.isRunning();
    	}
     
            // lance l'animation si elle est arrêtée, arrête l'animation si elle est lancée
    	public boolean toggleAnimation() {
    		if ( timer.isRunning() ) {
    			timer.stop();
    		}
    		else {
    			timer.start();
    		}
    		return timer.isRunning();
    	}
     
    	public void startAnimation() {
    		if ( !timer.isRunning() ) {
    			timer.start();
    		}
    	}
     
    	public void stopAnimation() {
    		if ( timer.isRunning() ) {
    			timer.stop();
    		}
    	}
     
            // méthode qui déplace le mobile
    	private void animate() {
    		final int width=getWidth();
    		final int height=getHeight();
    		boolean move=false;
    		if ( dx!=0 ) { // si on déplace sur l'axe horizontal
    			move=true;
    			int ddx=dx*v; // calcul du déplacement effectif (sens déplacement fois vitesse)
    			if ( x+ddx+WIDTH>=width ) { // si on sort (on dépasse le bord droit ici)
    				x=width-WIDTH; // on plaque contre le bord
    				dx=-dx; // on inverse le sens de déplacement
    			}
    			else if ( x+ddx<0 ) { // idem bord gauche
    				x=0;
    				dx=-dx;
    			}
    			else { // si on sort pas, on déplace
    				x+=ddx;
    			}
    		}
    		if ( dy!=0 ) { // idem pour axe vertical
    			move=true;
    			int ddy=dy*v;
    			if ( y+ddy+HEIGHT>=height) {
    				y=height-HEIGHT;
    				dy=-dy;
    			}
    			else if ( y+ddy<0 ) {
    				y=0;
    				dy=-dy;
    			}
    			else {
    				y+=ddy;
    			}
    		}
    		if ( move ) { // si on a déplacé, alors on redessine
    			repaint();
    		}
    	}
     
    	@Override
    	protected void paintComponent(Graphics g) {
    		super.paintComponent(g);
    		g.setColor(getForeground());
    		g.fillOval(x, y, WIDTH, HEIGHT);
    	}	
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame("Démo");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    		AnimationDemo anim = new AnimationDemo();
    		anim.setBackground(Color.BLACK);
    		anim.setForeground(Color.ORANGE);
    		frame.add(anim);
     
    		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
     
    		JButton startStopButton = new JButton("Start");
    		startStopButton.addActionListener(e->{
    			if ( anim.toggleAnimation() ) {
    				startStopButton.setText("Stop");
    			}
    			else {
    				startStopButton.setText("Start");
    			}
    		});
    		buttonPanel.add(startStopButton);
     
    		JPanel padPanel = new JPanel(new GridBagLayout());
     
    		int[] arrowButtons = {BasicArrowButton.NORTH_WEST,
    				              BasicArrowButton.NORTH,
    				              BasicArrowButton.NORTH_EAST,
    				              BasicArrowButton.WEST,
    				              BasicArrowButton.CENTER,
    				              BasicArrowButton.EAST,
    				              BasicArrowButton.SOUTH_WEST,
    				              BasicArrowButton.SOUTH,
    				              BasicArrowButton.SOUTH_EAST};
     
    		int indexButton=0;
    		for(int j=-1; j<2; j++) {
    			for(int i=-1; i<2; i++) {
    				final JButton button = new BasicArrowButton(arrowButtons[indexButton++]);
    				final int dx=i;
    				final int dy=j;
    				button.addActionListener(e-> anim.setDeplacement(dx,dy));
    				padPanel.add(button,new GridBagConstraints(i+1, j+1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,0), 0,0));
    			}
    		}
    		buttonPanel.add(padPanel);
    		JSpinner vitesseSpinner = new JSpinner(new SpinnerNumberModel(4, 1, 8, 1));
    		vitesseSpinner.addChangeListener(e-> anim.setVitesse((Integer)vitesseSpinner.getValue()));
    		anim.setVitesse((Integer)vitesseSpinner.getValue());
     
    		buttonPanel.add(vitesseSpinner);
    		frame.add(buttonPanel,BorderLayout.SOUTH);
     
    		KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e-> {
    			if ( e.getID()==KeyEvent.KEY_PRESSED ) {
    				switch(e.getKeyCode()) {
    				case KeyEvent.VK_LEFT:
    					anim.setDeplacementX(-1);
    					break;
    				case KeyEvent.VK_RIGHT:
    					anim.setDeplacementX(1);
    					break;
    				case KeyEvent.VK_UP:
    					anim.setDeplacementY(-1);
    					break;
    				case KeyEvent.VK_DOWN:
    					anim.setDeplacementY(1);
    					break;
    				case KeyEvent.VK_ESCAPE:
    					anim.setDeplacement(0,0);
    					break;
    				}
    			}
    			return false;
    		});
     
    		frame.setSize(300, 300);
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
     
    	}
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  6. #6
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Octobre 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 19
    Par défaut
    ok merci beaucoup, je vais prendre soin d'analyser ton code pour bien l'assimiler.

Discussions similaires

  1. Problème animation avec key
    Par swo.line dans le forum Flash
    Réponses: 0
    Dernier message: 03/06/2009, 22h24
  2. problème bannière animée avec lien vers autre site
    Par nanonerie dans le forum Flash
    Réponses: 1
    Dernier message: 19/05/2009, 21h10
  3. Probléme avec paintComponent()
    Par kiooik dans le forum Débuter
    Réponses: 2
    Dernier message: 18/09/2008, 20h23
  4. [Graphics] Problème avec paintComponent()
    Par Raiden1234 dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 11/02/2008, 19h50
  5. Problème anim flash avec IE
    Par jultoys dans le forum Flash
    Réponses: 1
    Dernier message: 15/05/2007, 16h18

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