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

Langage Java Discussion :

Problème boucle infinie


Sujet :

Langage Java

  1. #1
    Membre habitué
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Consultant fonctionnel
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2013
    Messages : 9
    Par défaut Problème boucle infinie
    Bonjour,
    J'ai besoin de votre aide pour comprendre le fonctionnement de Java dans le code qui va suivre. Il s'agit en fait d'une animation qui se lance au démarrage du programme. Deux boutons sont là pour arrêter l'animation pour le premier et pour relancer l'animation pour le deuxième bouton.

    Au clic sur le bouton "Stopper" l'animation s'arrête, mais ensuite, en cliquant sur le bouton "Go", l'animation n'est pas relancée. Il semble que c'est à cause de la boucle infinie mais j'arrive pas à comprendre pourquoi d'autant plus que le programme, au lancement, se trouve bien dans une boucle infinie, mais arrive quand même à fonctionner (animation qui tourne). Quelqu'un aurait-il plus d'explications sur ce "dysfonctionnement".

    Merci d'avance.

    Ci-dessous le code :
    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
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
     
    public class Fenetre extends JFrame{
     
      private Panneau pan = new Panneau();
      private JButton bouton = new JButton("Go");
      private JButton bouton2 = new JButton("Stop");
      private JPanel container = new JPanel();
      private JLabel label = new JLabel("Le JLabel");
      private int compteur = 0;
      private boolean animated = true;
      private boolean backX, backY;
      private int x, y;
     
      public Fenetre(){
        this.setTitle("Animation");
        this.setSize(300, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
     
        container.setBackground(Color.white);
        container.setLayout(new BorderLayout());
        container.add(pan, BorderLayout.CENTER);
        bouton.addActionListener(new BoutonListener());
        bouton.setEnabled(false);
        bouton2.addActionListener(new Bouton2Listener());
     
        JPanel south = new JPanel();
        south.add(bouton);
        south.add(bouton2);
        container.add(south, BorderLayout.SOUTH);
        Font police = new Font("Tahoma", Font.BOLD, 16);
        label.setFont(police);
        label.setForeground(Color.blue);
        label.setHorizontalAlignment(JLabel.CENTER);
        container.add(label, BorderLayout.NORTH);
        this.setContentPane(container);
        this.setVisible(true);
        go();
      }
     
      private void go(){
        //Les coordonnées de départ de notre rond
        x = pan.getPosX();
        y = pan.getPosY();
        //Dans cet exemple, j'utilise une boucle while
        //Vous verrez qu'elle fonctionne très bien
        while(this.animated){
          if(x < 1)backX = false;
          if(x > pan.getWidth()-50)backX = true;         
          if(y < 1)backY = false;
          if(y > pan.getHeight()-50)backY = true;
          if(!backX)pan.setPosX(++x);
          else pan.setPosX(--x);
          if(!backY) pan.setPosY(++y);
          else pan.setPosY(--y);
          pan.repaint();
     
          try {
            Thread.sleep(3);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }    
      }
     
      class BoutonListener implements ActionListener{
        public void actionPerformed(ActionEvent arg0) {
          animated = true;
          bouton.setEnabled(false);
          bouton2.setEnabled(true);
          go();
        }
      }
     
      class Bouton2Listener implements ActionListener{
         public void actionPerformed(ActionEvent e) {
          animated = false;    
          bouton.setEnabled(true);
          bouton2.setEnabled(false);
        }
      }    
    }

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Il ne faut pas utiliser de boucle infini dans le thread graphique, sous peine de bloquer l'application.
    Si tu veux faire une animation il faut utiliser un Timer : http://javasearch.developpez.com/j2s...ing/Timer.html


    a++

  3. #3
    Membre habitué
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Consultant fonctionnel
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2013
    Messages : 9
    Par défaut
    Salut,
    Au fait, étant encore débutant je cherche à comprendre le pourquoi du comment. Dans le cas d'espèce, je chercher à comprendre pourquoi l'application plante. Sachant que la création d'un nouveau thread dans le bouton fait bien relancer l'animation.

    A vous lire.

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Parce que tu bloques le thread graphique, nommé EDT (Event Dispatch Thread)


    Dès que tu affiches une fenêtre, l'EDT se lance et il va tourner jusqu'à la fin de l'application.
    Ce thread correspond en fait à une boucle infini qui va traiter les opérations graphiques en boucle, afin de mettre à jour l'affichage et de traiter les évènements...

    Ces tâches doivent être le plus brève possible, car sinon tu vas décaler tous les autres traitements.


    On peut voir cela facilement avec un code comme celui-ci :
    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
    		JProgressBar progress = new JProgressBar();
    		progress.setIndeterminate(true);
     
    		final JButton button = new JButton("Task");
    		button.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent event) {
    				try {
    					Thread.sleep(3000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    		});
     
    		Object[] message = { progress, button };
    		JOptionPane.showMessageDialog(null, message);
    La progressBar est animé... mais toute l'interface se bloque lorsque tu cliques sur le bouton "Task", car il bloque l'EDT pendant 3 secondes.


    Bref : pas de boucle infini dans l'EDT.
    Pour les animations il faut utiliser les Timer, et pour executer une tâche "longue" il faut utiliser un Thread ou un SwingWorker...


    a++

  5. #5
    Membre habitué
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Consultant fonctionnel
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2013
    Messages : 9
    Par défaut
    Merci. Le seul point qui reste intriguant pour moi est au niveau du premier lancement de l'application. On entre dans une boucle infinie mais l'EDT n'est pas bloqué et l'animation fonctionne. Une explication à cela?

  6. #6
    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,
    Citation Envoyé par Hafa10 Voir le message
    Merci. Le seul point qui reste intriguant pour moi est au niveau du premier lancement de l'application. On entre dans une boucle infinie mais l'EDT n'est pas bloqué et l'animation fonctionne. Une explication à cela?
    Parce que probablement que ta méthode main est comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public static void main(String[] args) {
     
        new Fenetre();
     
    }
    La méthode main() s'exécute dans un thread, le thread main, qui n'est pas l'EDT. Donc l'invocation de go qui lance l'animation n'est pas faite dans l'EDT, et donc la boucle ne l'est pas plus.

    En réalité, ce que tu fais dans la méthode main() est une tolérance mais contrevient à la bonne manière de créer et afficher une JFrame (cela fonctionne sur certaines JVM, mais ce n'est pas garanti. La bonne manière étant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public static void main(String[] args) {
     
        SwingUtilities.invokeLater(()-> new Fenetre());
     
    }
    Ou (en Java <8) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static void main(String[] args) {
     
        SwingUtilities.invokeLater(new Runnable() {
           public void run() {
              new Fenetre());
           }
        });
     
    }
    Ce qui force l'exécution du new Fenetre() sur l'EDT : et là ton animation au démarrage ne fonctionnera pas, pour les raisons invoquées par @AdiGuba.
    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.

  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    En fait tant que la fenêtre n'est pas affichée il reste possible de la créer/modifier dans un autre Thread que l'EDT.
    Par contre une fois visible cela peut poser des problèmes.

    Au passage avec Java 8 pour lancer un code dans l'EDT on peut aussi utiliser une référence de méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public static void main(String[] args) {
        SwingUtilities.invokeLater(MaClasse::startOnEdt);
    }
     
    private static void startOnEDT() {
        // ... code ...
    }



    Sinon il vaut mieux utiliser un Timer qu'un Thread.
    L'accès aux propriétés des composants doit se faire dans l'EDT, sinon tu risques d'avoir des valeurs "incohérentes" surtout si le composant peut être manipuler par d'autres evènements.
    Or Timer permet d’exécuter le code dans l'EDT à intervalle régulier, et c'est justement ce dont on a besoin ici.

    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
    	Timer timer = null;
     
    	private void go() {
    		stopAnimation();
    		this.x = pan.getPosX();
    		this.y = pan.getPosY();
    		// Un delai de 3ms c'est peut-être beaucoup
    		// avec 16ms on a déjà du 60fps c'est amplement suffisant.
    		this.timer = new Timer(3, this::updateAnimation);
    	}
     
    	private void stopAnimation() {
    		if (this.timer != null) {
    			this.timer.stop();
    		}
    	}
     
    	private void updateAnimation(ActionEvent event) {
    		if (x < 1)
    			backX = false;
    		if (x > pan.getWidth() - 50)
    			backX = true;
    		if (y < 1)
    			backY = false;
    		if (y > pan.getHeight() - 50)
    			backY = true;
    		if (!backX)
    			pan.setPosX(++x);
    		else
    			pan.setPosX(--x);
    		if (!backY)
    			pan.setPosY(++y);
    		else
    			pan.setPosY(--y);
    		pan.repaint();
    	}

    Bien sûr en Java 7 et inférieur on devra utiliser une classe anonyme à la place de la référence de méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    		// Java 8 :
    		this.timer = new Timer(3, this::updateAnimation);
    		// Java 7 et inférieur :
    		this.timer = new Timer(3, new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent event) {
    				updateAnimation(event);
    			}
    		});


    a++

  8. #8
    Membre habitué
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Consultant fonctionnel
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2013
    Messages : 9
    Par défaut
    Merci à vous. Cela est plus clair maintenant.

    Une dernière question, si vous permettez. En forçant l'application à s'exécuter dans l'EDT dès le lancement, l'animation n'est certes pas lancée et c'est logique, mais ce qui me parait bizarre que le programme arrive à afficher la fenêtre avec, entre autres, les dimensions choisies et la couleur de fond blanche, mais sans les boutons. Pourtant, l'affichage du contentpane et des boutons qui s'y trouvent devrait s'effectuer avant d'entrer dans la méthode go, et donc dans la boucle infinie. Comment est-ce possible?

  9. #9
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Pas forcément car certains traitements peuvent être différés.
    Par exemple lorsque tu ajoutes un composant dans une JFrame, tu ne fais que le lien entre le composant et la fenêtre en mémoire.
    L'affichage du composant est prévu lors de la prochaine mise à jour de l'affichage.

    Bien sûr en temps normal ce différé ne se voit pas car cela vient immédiatement après.
    Mais si tu bloques le thread ce ne pourra pas être fait...


    a++

  10. #10
    Membre habitué
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Consultant fonctionnel
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2013
    Messages : 9
    Par défaut
    Merci!

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

Discussions similaires

  1. [XL-2007] Problème boucle infinie
    Par s.byczek dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 08/02/2012, 14h49
  2. [XL-2010] Problème boucle infini
    Par Zaelos dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 24/01/2012, 10h49
  3. problème boucle infinie
    Par hanou88 dans le forum C
    Réponses: 7
    Dernier message: 05/11/2010, 01h15
  4. Problème de boucle infinie...
    Par anne-so dans le forum Langage
    Réponses: 1
    Dernier message: 25/04/2006, 14h10
  5. [JMeter] Problème avec la boucle infinie pour les tests
    Par zegreg dans le forum Tests et Performance
    Réponses: 1
    Dernier message: 05/10/2005, 11h41

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