Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème de thread.sleep ()

Mouvement de JPanel

Sujet résolu
    4 novembre 2008 à 11:16:18

    Bonjour à tous,

    je vous expose mon problème.

    J'ai une JFrame qui contient :

    JButton btn
    JPanel  pan
    


    à l'origine, mon JPanel est colorié en rouge. (Background).
    Bon.

    Je souhaiterai faire clignoter mon JPanel (le faire passer de rouge à bleu) lors du clique sur le bouton.
    J'appelle donc ce code lors du clic :

    for (int i = 0 ; i < 20 ; i ++)
    	{
    		this.jPanel1.setBackground (java.awt.Color.RED);
    		this.jPanel1.repaint ();
    		Util.pause (50);
    		
    		this.jPanel1.setBackground (java.awt.Color.BLUE);
    		this.jPanel1.repaint ();
    		Util.pause (50);
    
    	}
    


    où Util.pause est :

    public class Util
    {
    	public static void pause (int _temps)
    	{
    		try
    		{
    			Thread.sleep(_temps) ;
    		}
    		catch (InterruptedException e)
    		{
    			e.printStackTrace() ;
    		}
    	}	
    }
    


    Bon.
    ça devrait marcher... Mais...
    ça ne marche pas :colere2:

    La pause se fait bien, pas de soucis. Mais le clignotement non.
    Le panel passe de ROUGE à BLEU directement, mais avec un délais (ce qui prouve que le Util.pause () marche).

    Avez vous une idée?

    Je vous remercie
    • Partager sur Facebook
    • Partager sur Twitter
      4 novembre 2008 à 15:33:29

      Tu as mis ce code directement dans le actionPerformed ?
      Ton panel devient-il bleu tout de suite après le clic ou après le délai total de 20*50ms=1s ? (augmente les pauses si tu n'as pas le temps de voir)
      • Partager sur Facebook
      • Partager sur Twitter
        4 novembre 2008 à 18:21:02

        Oui direct dans le ActionPerformed.

        Le Panel devient bleu après environ 1s.

        Si je fais un System.out.Println ("toto") dans la boucle,
        alors, les Toto seront bien affichés toutes les 50ms ou plus si j'augmente le délais.

        Seul le repaint() semble ne pas être appelé.
        • Partager sur Facebook
        • Partager sur Twitter
          5 novembre 2008 à 5:53:34

          Je le savais ! C'est normal que tu aies ce problème. Par contre ça va être difficile de t'expliquer ce qui se passe... C'est un problème de thread, plus exactement l'Event-Dispatch-Thread.

          En attendant d'avoir une idée pour t'expliquer ça de manière simple et compréhensible, parce que je n'ai pas d'idée pour le moment, voici une solution possible :

          Runnable r = new Runnable(){
          public void run () {
          for (int i = 0 ; i < 20 ; i ++) 	{
          		jPanel1.setBackground (java.awt.Color.RED);
          		jPanel1.repaint ();
          		Util.pause (50);
          				jPanel1.setBackground (java.awt.Color.BLUE);
          		jPanel1.repaint ();
          		Util.pause (50);
          	}
          }};
          
          (new Thread(r)).start();
          


          Note pour les puristes : il serait plus judicieux d'utiliser un executor ou un worker. Il s'agit ici d'une solution volontairement simplifiée, qui fonctionne certes, mais qui n'est, je l'admets, pas forcément très optimisée.

          Les explications suivront dans un edit ultérieur.
          • Partager sur Facebook
          • Partager sur Twitter
            5 novembre 2008 à 11:43:22

            Merci beaucoup !!
            Ça marche !

            Merci encore
            • Partager sur Facebook
            • Partager sur Twitter
              5 novembre 2008 à 18:04:35

              Réponse à ton post sur mon sujet (et donc celui-ci)
              Pour régler ton problème, il vaut mieux faire une boucle repaint() dans une autre classe extends Thread
              En gros, tu lances un Thread qui va repaint ton Jpanel en boucle (à toi de choisir combien de fois par secondes)
              • Partager sur Facebook
              • Partager sur Twitter
                6 novembre 2008 à 4:50:45

                Voici une explication sur ce qui se passe, j'espère que ce sera compréhensible parce que ce n'est pas facile à comprendre...

                Tous les messages/évènements système comme clic à la position X;Y, appui sur une touche, etc. sont gérés dans un thread unique que l'on appelle en java event-dispatch-thread (dans d'autres langages il a d'autres noms).
                Le repaint est un message provenant du système et qui est donc traité dans ce thread. En appelant la méthode repaint de java, tu vas dire à java de dire au système qu'il doit envoyer un message "paint" à java dès qu'il le peut. En recevant le message "paint" en provenance du système, j'ava va appeler la méthode paint(Graphics g) de la fenêtre qui va ensuite appeler celle des panels, des composants, etc. récursivement.
                Ainsi la méthode paint est toujours appelée dans le cadre de cet event-dispatch-thread.

                Ton actionPerformed est également appelé à partir du event-dispatch-thread puisqu'il s'agit à l'origine d'un évènement système lié à la fenêtre indépendament de java (p.ex. un clic de souris ou un appui sur espace (on peut imaginer d'autres façons d'appuyer sur un bouton)).

                En réponse à cette activation, tu changes le fond puis tu demandes à java de dire au système que ce dernier doit envoyer un message paint.
                Ensuite, tu commandes à l'event-dispatch-thread de dormir 50ms.
                Simplifions la procédure : disons que le système d'exploitation est chargé d'appeler la méthode paint de java. Or le thread qui est chargé de le faire est occupé (il dort et n'a pas rendu la main; en gros il n'est pas sorti d'actionPerformed donc il ne peut rien faire d'autre en attendant).
                Du coup, il ne se passe rien. Pas de paint donc tu ne peux pas voir le changement de couleur.

                Après 1s, actionPerformed se termine et le thread est enfin libre pour pouvoir appeler paint. Il va donc enfin le faire (20 fois de suite!) et c'est donc à ce moment-là que tu verras le dernier changement de couleur effectué, bleu en l'occurence.

                J'espère que mes explications ont été instructives, claires et suffisament compréhensibles. J'avoue que ce n'est vraiment pas évident.
                • Partager sur Facebook
                • Partager sur Twitter
                  6 novembre 2008 à 22:49:21

                  JE te remercie grandement ^^
                  J'ai eu ce problème la semaine dernière, or personne n'a pût m'aider et j'ai "trouvé" tout seul en créant un thread de repaint (et un thread pour ma boucle), car je m'étais aperçu que le thread principal "ne rendait pas la main" tant que la boucle n'était pas finie, malgré mes sleep et yield.
                  Avec cette explication, je comprends mieux, c'est plus clair et me permet de voir java d'une différente manière (et comprendre une plus grande partie du fonctionnement de java et de ses Thread)

                  Encore merci

                  P.S.: Dans mon post précédent, je me suis trompé, c'est ta boucle qu'il faut mettre dans un Thread différent du principal afin que tes sleep servent réellement (c'est d'ailleurs ce qu'a fait QuentinC 2 si je ne me trompe pas ???
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Problème de thread.sleep ()

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown