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

EDT/SwingWorker Java Discussion :

Souci avec SwingWorker et JProgressBar


Sujet :

EDT/SwingWorker Java

  1. #1
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut Souci avec SwingWorker et JProgressBar
    hello,

    j'ai un souci pour mettre à jour une progressbar pendant un traitement long. J'ai essayé d'implémenter swingworker, j'ai l'impression d'avoir fait ce qu'il faut mais... ça ne marche pas ! Le traitement s'exécute, mais la barre n'est mise à jour qu'à la fin.
    Voilà quelques bouts de code :
    le swingworker :
    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
    public class CalculerDelaunay extends SwingWorker<Set<Triangle>, Integer>{
     
    	private List<Pnt> sommets ;
     
    	public CalculerDelaunay(List<Pnt> sommets) {
    		this.sommets = sommets;
    	}
     
    	@Override
    	protected Set<Triangle> doInBackground()  {
    		Triangulation t = new Triangulation(sommets);
    		int i = 0 ;
    		for (Pnt point : sommets ){
    			t.delaunayPlace(point);
    			setProgress((int) 100 *i/sommets.size());
    			System.out.println((int) 100 *i/sommets.size()+1);
    			i++;
    		}
    		return t.getListeTriangle().nodeSet() ;
    	}
     
    	protected void done() {
    		setProgress(100);
    	}
    }
    L'appel (situé dans un actionperformed d'un actionlistener):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CalculerDelaunay calc = new CalculerDelaunay(sommets);
    						calc.addPropertyChangeListener(new PropertyChangeProgressBar(fenetre.getProgressBar()));
    						calc.execute();
    et mon listener :
    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
    public class PropertyChangeProgressBar implements PropertyChangeListener {
    	private JProgressBar progressBar ;
     
    	private PropertyChangeProgressBar(){
     
    	}
     
    	public PropertyChangeProgressBar(JProgressBar pB){
    		progressBar = pB ;
    	    progressBar.setValue(0);
    	}
    	@Override
    	public void propertyChange(PropertyChangeEvent evt) {
    		String strPropertyName = evt.getPropertyName();
    		System.out.println(strPropertyName);
    	    if ("progress".equals(strPropertyName)) {
    	      progressBar.setIndeterminate(false);
    	      int progress = (Integer)evt.getNewValue();
    	      progressBar.setValue(progress);
    	    }
    	}
    }
    Je ne vois pas bien d'où vient le problème... j'ai mis un syso dans mon listener, et il n'est appelé qu'à la fin !

    Quelqu'un a t'il une idée ? S'il faut que je place plus de code, pas de problème.

  2. #2
    Expert éminent sénior
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Essaie d'enlever cet appel:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    progressBar.setIndeterminate(false);
    de ton propertyChange
    Hey, this is mine. That's mine. All this is mine. I'm claiming all this as mine. Except that bit. I don't want that bit. But all the rest of this is mine. Hey, this has been a really good day. I've eaten five times, I've slept six times, and I've made a lot of things mine. Tomorrow, I'm gonna see if I can't have sex with something.

  3. #3
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    Bonjour,

    merci de la suggestion, mais ça ne change rien.

    à bientôt,

  4. #4
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Tu as combien d'élément dans ta liste ? Le traitement est-il rapide ?

    Il y a des chances que cela soit trop rapide pour voir la progression : le setProgress() n'engendre pas obligatoirement un évènement. En fait s'il y a plusieurs setProgress() "rapproché" dans le temps, seul le dernier sera pris en compte Sinon tu vas passer plus de temps à afficher la progression qu'à faire ton traitement.


    a++

  5. #5
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    hello,

    j'ai 3000 éléments dans la liste, donc effectivement chaque traitement est rapide, le traitement total dure une quinzaine de secondes. Le souci, c'est que je voudrais que mon traitement puisse fonctionner pour des listes 10 à 20 fois plus importantes, dois-je ne faire un setProgress que toutes les 10 ou 50 occurences du coup ?

  6. #6
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Niun Voir le message
    j'ai 3000 éléments dans la liste, donc effectivement chaque traitement est rapide, le traitement total dure une quinzaine de secondes.
    Sur une quinzaine de seconde tu devrais bien voir la progression pourtant !

    C'est bien le parcours de la liste qui prend ce temps ? Ou le constructeur de Triangulation ?

    Citation Envoyé par Niun Voir le message
    Le souci, c'est que je voudrais que mon traitement puisse fonctionner pour des listes 10 à 20 fois plus importantes, dois-je ne faire un setProgress que toutes les 10 ou 50 occurences du coup ?
    Justement non normalement tu n'as rien à faire : tu appels setProgress() régulièrement et ils seront automatiquement ignoré si trop rapproché. Cela s'adapte bien que le traitement soit rapide ou lent...


    Bizarre

    a++

  7. #7
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    non, c'est bien la boucle qui prend ce temps, quand je met un sysout dans la boucle, je vois le pourcentage qui monte doucement, tout comme je voudrais

    et quand je met un sysout dans le propertyChange, je vois qu'il n'est trigger qu'à la fin de mon traitement.

    J'ai peut-être une piste qu'il faut que je creuse : la principale différence que je vois dans mon code par rapport aux exemples est que je construis mon worker et je lui affecte un listener à l'intérieur d'un actionPerformed (en gros, quand je clique sur le bouton "lancement"). Est-ce que ça pourrait jouer ? Si oui c'est un peu tordu, car je ne dispose pas des éléments me permettant d'initialiser mon worker dans ma frame principale, il faudrait donc que je le crée, que je lui mette son listener, et que j'ai une méthode "initialisation" que j'appelle dans l'actionPerformed... bon ça se tente, je vais regarder ça.

  8. #8
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    Bon ma piste ne fonctionne pas, j'ai exactement le même problème en initialisant le worker et en lui collant le listener dans la frame principale.

    Du coup si quelqu'un a une autre idée, je prends.

  9. #9
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Par curiosité : que fait t.delaunayPlace(point) ???


    a++

  10. #10
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    Mon programme est une triangulation de delaunay : on a un paquet de point qu'on veut relier d'une manière particulière. Du coup, on initialise avec un grand triangle qui contient tous les points, puis on place les points les uns après les autres, en construisant les triangles les plus pertinents et éventuellement en en détruisant d'autres. Si le code t'intéresse, je le livre d'autant plus facilement que le gros du boulot n'a pas été fait pas moi et est libre.

  11. #11
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    En fait je voudrais surtout savoir si les traitements de cette méthode touchent l'EDT ou pas ?


    a++

  12. #12
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    non pas du tout c'est une classe métier qui ne connaît aucun composant graphique.

  13. #13
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Et quel est le code complet de l'actionperformed ?

    Y'a moyen d'avoir un code compilation qui ne soit pas trop long ?


    a++

  14. #14
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    Voilà la classe ActionCalculerDelaunay en entier : c'est très simple, on importe le fichier d'entrée, on calcule, et on exporte.
    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
    package ihm;
     
    import io.Export;
    import io.Import;
     
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
     
    import javax.swing.JOptionPane;
     
    import delaunay.Graph;
    import delaunay.Pnt;
    import delaunay.Triangle;
    import delaunay.Triangulation;
    import delaunay.TriangulationDansContour;
     
    public class ActionCalculerDelaunay implements ActionListener {
    	private Fenetre fenetre ;
     
    	public ActionCalculerDelaunay(Fenetre fenetre) {
    		this.fenetre = fenetre ;
    	}
     
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		String pathEntree = fenetre.getPanSommet().getPath();
    		String pathSortie = fenetre.getPanSortieDelaunay().getPath();
    		String pathContour = fenetre.getPanContour().getPath();
    		boolean ignorerPremiereLigneSommets = fenetre.getPanSommet().isCoche() ;
    		boolean ignorerPremiereLigneContour = fenetre.getPanContour().isCoche() ;
    		boolean importOk = false ;
    		if (pathEntree.equals("")){
    			JOptionPane.showMessageDialog(fenetre, "Vous n'avez pas choisi un fichier de sommets !","Erreur",JOptionPane.ERROR_MESSAGE);
    		}else {
    			if (pathSortie.equals("")){
    				JOptionPane.showMessageDialog(fenetre, "Vous n'avez pas choisi un fichier de sortie pour la triangulation !","Erreur",JOptionPane.ERROR_MESSAGE);
    			}else {
     
    				List<Pnt> sommets ;
    				List<List<Pnt>> contour ;
    				try {
    					if (pathContour.equals("")){
    						sommets = Import.ImportSommets(pathEntree,ignorerPremiereLigneSommets);
    						CalculerDelaunay calc = new CalculerDelaunay(sommets);
    						calc.addPropertyChangeListener(new PropertyChangeProgressBar(fenetre.getProgressBar()));
    						calc.execute();
    						Export.ecrireTriangulation(calc.get(), pathSortie);
    						importOk = true ;
    					}else {
    						sommets = Import.ImportSommets(pathEntree,ignorerPremiereLigneSommets);
     
    						try {
    							contour = Import.ImportContour(pathContour,ignorerPremiereLigneContour);
    							Triangulation t = new Triangulation(sommets);
    							int i = 0 ;
    							for (Pnt point : sommets ){
    								t.delaunayPlace(point);
    							}
    							Graph<Triangle> result = TriangulationDansContour.enleverTrianglesContours(t.getListeTriangle(), contour);
    							Export.ecrireTriangulation(result.nodeSet(), pathSortie);
    							importOk = true ;
    						}
    						catch (FileNotFoundException fi){
    							JOptionPane.showMessageDialog(fenetre, "Le fichier de contour sélectionné en entrée n'existe pas !","Erreur",JOptionPane.ERROR_MESSAGE);
    						}
    						catch (NumberFormatException f) {
    							JOptionPane.showMessageDialog(fenetre, "Le fichier de contour que vous avez soumis en entrée n'est pas au bon format","Erreur",JOptionPane.ERROR_MESSAGE);
    						} 
    					}	
    				}
    				catch (FileNotFoundException f) {
    					JOptionPane.showMessageDialog(fenetre, "Le fichier de sommets sélectionné en entrée n'existe pas !","Erreur",JOptionPane.ERROR_MESSAGE);
    					f.printStackTrace();
    				} 
    				catch (NumberFormatException f) {
    					JOptionPane.showMessageDialog(fenetre, "Le fichier de sommets que vous avez soumis en entrée n'est pas au bon format","Erreur",JOptionPane.ERROR_MESSAGE);
    				} 
    				catch (IOException f) {
    					JOptionPane.showMessageDialog(fenetre, "Problème d'entrée/sortie","Erreur",JOptionPane.ERROR_MESSAGE);
    				} catch (InterruptedException f) {
    					// TODO Auto-generated catch block
    					f.printStackTrace();
    				} catch (ExecutionException f) {
    					// TODO Auto-generated catch block
    					f.printStackTrace();
    				}
    				if (importOk) {
     
    				}
     
     
    			}
    		}
     
    	}
     
    }
    Qu'entends tu par un code compilation ?

  15. #15
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Niun Voir le message
    Qu'entends tu par un code compilation ?
    Un code compilable... C'est à dire un code avec le strict minimum qui puisse être copier/coller dans un EDI pour exécuter le programme (et donc reproduire le problème).

    Ce qui n'est pas le cas de ton code car il manque plein de chose





    Mais cherches pas j'ai trouvé l'origine de ton problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	calc.execute();
    		Export.ecrireTriangulation(calc.get(), pathSortie);
    Tu exécutes le SwingWorker en tâche de fond (bien !), mais la ligne d'après tu récupères son résultat via get(), ce qui va bloquer le thread courant, c'est à dire l'EDT (pas bien !)

    Comme l'EDT est bloqué il ne peut rien faire du tout : ni mettre à jour l'affichage, ni gérer les événements, ni les actions comme setProgress(). Du coup totu est empilé et exécuté à la fin une fois que l'EDT est débloqué...



    Je suppose que Export.ecrireTriangulation() génère un fichier ou autre chose. Dans ce cas il serait préférable d'effectuer ceci dans ton SwingWorker à la fin de ta méthode doInBackground()


    a++

  16. #16
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 42
    Points : 18
    Points
    18
    Par défaut
    Merci !!!! J'ai relu le tuto de Romain, qui le disait bien pourtant... honte à moi... Bon ça marche du coup je suis bien content. ça me permet aussi de mesurer l'étendue des progrès que j'ai encore à faire avec ces histoires de thread...

    Encore merci, bonne après-midi

    edit : en y repensant me vient une question : est-ce que du coup mon export n'aurait pas plus sa place dans la méthode done ? Je ne comprends pas bien la différence entre mettre des instructions à la fin de doInbBackgrount ou dans done ? bon là on est dans le raffinage je pense...

  17. #17
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Non : le done() est exécuté dans l'EDT !


    Pour bien comprendre : l'EDT est chargé de l'interface graphique et de tout ce qui s'y rapporte. Dès que tu touches à l'interface graphique tu dois le faire dans l'EDT.

    En fait l'EDT ce n'est rien d'autre qu'une boucle infini qui traitent ses tâches :
    • repaint() des composants.
    • gestion des évènements (souris, clavier, etc) via l'appel des listeners.
    • Autre tâches diverses (invokeLater(), javax.swing.Timer, done()/setProgress()/publish() du SwingWorker, ...)


    Donc dès qu'une tâche de l'EDT prend trop de temps, cela retarde d'autant plus les tâches suivantes, ce qui provoque un "gel" de l'interface




    Le SwingWorker permet de simplifier tout cela :
    • Tu exécutes tes tâches longues dans un thread à part via doInBackground() (pour pas bloquer l'EDT).
    • Tu peux utiliser setProgress() pour générer un évènement adéquat dans l'EDT, en évitant de le faire trop souvent pour ne pas le surcharger inutilement.
    • La méthode done() est exécuté à la fin dans l'EDT, et peut récupérer de doInBackground() (via get()). Cela permet de mettre à jour ton interface à la fin du traitement...
    • Avec publish()/process() tu peux éventuellement envoyer des résultat vers l'EDT pendant le traitement...



    a++

Discussions similaires

  1. JProgressBar et Thread avec SwingWorker
    Par sebastien61 dans le forum EDT/SwingWorker
    Réponses: 5
    Dernier message: 13/05/2009, 16h08
  2. quelques soucis avec word 2000
    Par ramchou dans le forum Word
    Réponses: 3
    Dernier message: 06/09/2004, 18h13
  3. souci avec un algorithme
    Par slider16 dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 22/03/2004, 17h17
  4. [DEBUTANT] petits soucis avec un prgm de chat
    Par LechucK dans le forum MFC
    Réponses: 8
    Dernier message: 19/01/2004, 16h52
  5. Réponses: 4
    Dernier message: 16/02/2003, 12h16

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