Mon sleep empèche le repaint()

Poilamazout Messages postés 5 Date d'inscription mercredi 29 avril 2009 Statut Membre Dernière intervention 1 mai 2009 - 29 avril 2009 à 17:50
cs_DARKSIDIOUS Messages postés 15814 Date d'inscription jeudi 8 août 2002 Statut Membre Dernière intervention 4 mars 2013 - 1 mai 2009 à 15:27
Bonjour,

J'ai un sleep précedé d'un repaint(), le tout situé dans une boucle for, qui devrait normalement m'afficher des tableaux à des intervalles de 1 seconde. Pourtant quand je lance le thread, le programme fonctionne correctement au niveau des calculs mais ne raffraichi l'image qu'à la fin. Est-ce le sleep(1000) qui empeche le rafraichissement?
en simplifiant, mon code ressemble à ça:

import java.awt.BorderLayout;

public class Tempo extends Thread
{   
    private Fenetre ffFenetre;
   
    public Tempo()
    {   
        Fenetre fFenetre=new Fenetre();
        fFenetre.setVisible(true);
        this.ffFenetre=fFenetre;
    }

    public void run()
    {
       
        ffFenetre.getjBLancer().addActionListener(new java.awt.event.ActionListener(){
            public void actionPerformed(java.awt.event.ActionEvent e) {
               
 
           
                               
                for(i=0;i<10;i++)
                {
                   
                    if(ffFenetre.getProche().isSelected()==true){
                    ffFenetre.getCombat().combatProche();           <=cette méthode se lance correctement
                    ffFenetre.setJPanelTableau();                           <=méthode contenant "jPanelTableau.repaint();"
                    }
                    else{
                        ffFenetre.getCombat().combat();
                        ffFenetre.setJPanelTableau();
                    }
                                       
                   
                    try
                    {
                          
            sleep(1000);

                    }
                    catch(InterruptedException eE){}
           
                }
              
        });
       
    }
   
}

7 réponses

cs_DARKSIDIOUS Messages postés 15814 Date d'inscription jeudi 8 août 2002 Statut Membre Dernière intervention 4 mars 2013 130
29 avril 2009 à 18:07
Normal, tu fais le refresh et les calculs dans le même thread que le thread d'affichage de SWING : il faut faire les calculs dans un thread à part, et laisser le thread d'affichage de SWING gérer l'affichage...

Grosso modo, au lieu de faire (c'est juste l'idée, à toi d'adapter) :
public void run()
{

ffFenetre.getjBLancer().addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e) {




for(i=0;i<10;i++)
{

if(ffFenetre.getProche().isSelected()==true){
ffFenetre.getCombat().combatProche(); <=cette méthode se lance correctement
ffFenetre.setJPanelTableau(); <=méthode contenant "jPanelTableau.repaint();"
}
else{
ffFenetre.getCombat().combat();
ffFenetre.setJPanelTableau();
}


try
{

sleep(1000);

}
catch(InterruptedException eE){}

}

});

}

Faire :

ffFenetre.getjBLancer().addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for(i=0;i<10;i++)
{
if(ffFenetre.getProche().isSelected()){
ffFenetre.getCombat().combatProche();
ffFenetre.setJPanelTableau();
}
else{
ffFenetre.getCombat().combat();
ffFenetre.setJPanelTableau();
}
}
});

}
0
Poilamazout Messages postés 5 Date d'inscription mercredi 29 avril 2009 Statut Membre Dernière intervention 1 mai 2009
1 mai 2009 à 12:02
J'ai découvert cette méthode de invokeLater et l'ai essayé, cependant même si je sais que le code qu'il contient est partiellement lu, vu qu'il m'affiche les println, le code qui dépend d'une autre classe qui est  ffFenetre.getCombat().combat() ne se lance pas.... il faut aussi lui mettre l' instance ffFenetre en attribut pour qu'il puisse l'utiliser?
0
Poilamazout Messages postés 5 Date d'inscription mercredi 29 avril 2009 Statut Membre Dernière intervention 1 mai 2009
1 mai 2009 à 12:09
De plus, mon thread  (celui qui contient le swingUtilities.invokeLater) semble bloquer le invokeLater avec son sleep, car les println que j'ai mis dans invokeLater s'affichent tous d'un coup à la fin de toutes les tempos. Pourtant j'avais cru comprendre que InvokeLater lançait un nouveau thread indépendant du premier, ce qui permettait d'effectuer certaines taches même si le premier thread est en attente.
J'ai tout faux?
0
Poilamazout Messages postés 5 Date d'inscription mercredi 29 avril 2009 Statut Membre Dernière intervention 1 mai 2009
1 mai 2009 à 14:58
J'ai essayé le invokeLater sur un autre programme plus simple, et ça a eu l'air de fonctionner. Il semblerait que problème n'intervient qu'en présence d'un ActionListener . Quelqu'un aurait un semblant d'explication?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_DARKSIDIOUS Messages postés 15814 Date d'inscription jeudi 8 août 2002 Statut Membre Dernière intervention 4 mars 2013 130
1 mai 2009 à 15:00
Non non, le invoke listener fonctionne très bien, qu'il y ait un ActionListener ou non, d'ailleurs, tout les codes prenant un peu de temps doivent tous être exécuté dans un invokeLater afin de ne pas bloquer le thread d'affichage de SWING, sinon faut pas s'étonner qu'un programme java semble ramer !
0
Poilamazout Messages postés 5 Date d'inscription mercredi 29 avril 2009 Statut Membre Dernière intervention 1 mai 2009
1 mai 2009 à 15:11
Pourtant je viens de réessayer avec et sans Action listener:

sans: tout se déroule parfaitement, les deux thread fonctionnent en parrallèle sans se bloquer mutuellement.

avec: seul le thread principale fonctionne jusqu'a ce que sa méthode run soit finit, Puis le invokeLater se lance.

Je comprend pas bien non plus en quoi le action listener impliquerait un changement ...

Par exemple avec ce code:

package Interface;
import javax.swing.SwingUtilities;

import java.awt.BorderLayout;
import javax.swing.SwingUtilities;

public class Tempo extends Thread{
   
    private Fenetre ffFenetre;

    public Tempo()
    {   
        Fenetre fFenetre=new Fenetre();
        fFenetre.setVisible(true);
        this.ffFenetre=fFenetre;
    }

    public void run()
    {
      
        ffFenetre.getjBLancer().addActionListener(new java.awt.event.ActionListener(){
            public void actionPerformed(java.awt.event.ActionEvent e) {
               
                int i;

                for(i=0;i<5;i++){
                   
                    System.out.println("1");
                SwingUtilities.invokeLater(new Runnable(){
                        public void run(){
                            System.out.println("2");});

                    try
                    {          
                            sleep(1000);
                            System.out.println("4");
                    }
                    catch(InterruptedException eE){}
           
                }
               
            }
        });
       
    }
}

Il va m'afficher successivement 1 et 4 avec une tempo de 1 seconde, puis apres les avoir afficher 5 fois, il m'affiche quatre 2 d'un coup (et pas cinq, je ne sais pourquoi).
Par contre si j'enleve le action listener, il me fait les deux en parralèle et tout est nickel.
0
cs_DARKSIDIOUS Messages postés 15814 Date d'inscription jeudi 8 août 2002 Statut Membre Dernière intervention 4 mars 2013 130
1 mai 2009 à 15:27
normal, vu que tu fais un sleep dans ton événement !

Il ne faut surtout pas faire cà car tu bloque tout les événements de ton interface SWING pendant 4 secondes !

Je te conseille d'aller voir ceci :
http://www.javamex.com/tutorials/threads/invokelater.shtml
0
Rejoignez-nous