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 :

problème du pause (sleep) ou problème vitesse d'affichage (Swing)


Sujet :

EDT/SwingWorker Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Inscrit en
    Mai 2005
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 6
    Par défaut problème du pause (sleep) ou problème vitesse d'affichage (Swing)
    Hello !!!

    C'est rare que je poste un post sur les forrums ... mais là je suis à bout d'idées !
    Bref,
    Voilà mon soucis,

    J'ai crée une interface graphique pour mon programme, cettte interface me permet
    de gérer plusieurs paramètres du logiciel.
    Sur un des panels je peux lancer et arrêter les services principaux de ce soft!

    un service BS(BS.exe) et BA(BA.exe) ... jusque là tout va bien !
    (je peux arrêter et redémarrer mes services avec le gestionnaire de service windows!)

    Quand je click sur le boutton démarrer ou le boutton arrêter, toujours pas de soucis!
    tous fonctionne! mes services s'arrête et redémarre si je click sur l'un des boutton.
    Dans actionListener des bouttons j'executes des méthodes qui envois des commandes
    externe à java. - net star, et net Stop -
    les voici,

    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
    // une classe Service que j'ai créé pour Dem./Arrê. les services
     
    	public void Demarrage (String NomService)
    	{
    		try
    		{
    			cmd = Runtime.getRuntime().exec(new String [] {"net", "start", NomService,"/y"});
    		}
    		catch (IOException ExpDemarrage) 
    		{
    			ExpDemarrage.printStackTrace();
    		}	
    	}
     
     
    	public void Stop (String NomService)
    	{
    		try
    		{
    			cmd = Runtime.getRuntime().exec(new String [] {"net","stop", NomService,"/y"});
    		}
    		catch (IOException ExpStop) 
    		{
    			ExpStop.printStackTrace();
    		}	
    	}
    mon soucis !

    l'affichage d'une icone sur mon interface.
    Lorsque le service est démarré, j'ai un feux Vert.
    Lorsque le service est arrêté, j'ai un feux Rouge.

    dans un souccis d'efficacité et de sécurité,
    j'ai pensé à mettre un StandBye pendant l'arrêt et le redémarrage des services.
    afficher un feux Orange, et désactiver les buttons (Arrêter/Démarrer)
    pendant le démarrage ou l'arrêt des services.

    j'appelle pour cela une méthode, Attente. de la classe Service Que voici.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    	public void Attente (long tmp)
    	{
    		try
    		{
    			Thread.sleep(tmp);
    		}
    		catch (InterruptedException e)
    		{
    			e.printStackTrace(); 
    		}
    	}
    elle recoit en paramètre le temps d'attente.
    cela me permet de désactiver les bouton pour que l'utilisateur ne démarre pas
    et arrête aussi tôt les service. et pendant ce temp, j'affiche une icone en
    feux organe!

    OUF! vien enfin ma question,

    >> Service démarré le feu est vert
    >> j'arrête ...
    >> Tout se fige ! mes boutons incacessible (normal! j'ai demandé! mais bon pas complètement désac.)
    >> Le feux ne passe pas à l'orange ! pourtant le temps d'attente est de 5 secondes!
    >> sous windows le service c'est bien arrêté ...
    >> mon soft attent 5 seconde et me rend la main ... LE feu est ROUGE directe!
    Je n'ai pas vu le feux en orange ...

    voilà un bout de l'appli :

    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
    ...
    ImageIcon start = new ImageIcon (getClass().getResource("/img/start.png"));
    ImageIcon pause = new ImageIcon (getClass().getResource("/img/pause.png"));
    ImageIcon stop  = new ImageIcon (getClass().getResource("/img/stop.png"));
     
    // une classe Service que j'ai créé pour Dem./Arrê. les services e géré le temps d'attente.
    Service process = new Service (); 
    ...
    	public void actionPerformed (ActionEvent e)
        	{
        	...
    		if (e.getSource() == jButton1)
        		{
        			jLabel42.setIcon(pause);	// j'affiche l'icone Pause (ORANGE)
        			process.Stop("BS"); 		// je démarre le service BS
        			jButton1.setEnabled(false);	// je désactive le premier bouton
        			jButton2.setEnabled(false);	// je désactive l'autre bouton
        			process.Attente(5000); 		// j'attends 5000 miliSec. (5sec) 
        			jLabel42.setIcon(stop);		// j'affiche l'icone Stop (Rouge)	
        			jButton1.setEnabled(true);	// je Réactives les boutons
        			jButton2.setEnabled(true);	// je Réactives les boutons
    		}
     
    	...
    	}
    dans le fond tout fonctionne ... seulement tout se fige ... pendant la pause ...
    et le ne vois pas mon ... icone orange ...
    je suis sur que le service démarre ... juste par ce que à ce moment là c'est plus JAVA
    qui gère ... ma commande est passé à l'OS ... et c'est OS qui gere ... mon arrêt du service ...
    Les boutons ne sont pas désactivé ... il sont tout simplement bloqué ...
    car je ne les vois pas grisé ... (juste inacessible !)

    Est-ce une bonne méthode pour faire une pause ... dans le programme ... sans boufé de la resource??
    Car je soupsonne plus la méthde d'attente ... qui est Thread qui s'execute.
    mais j'ai bien demandé à mon icone de changé d'adord !
    ensuite désactiovation des bouton ...
    et ensuite la pause ...
    Hors ... j'ai l'impression que ... pas le temps ... de réagir ... que déjà le Thread s'execute !

    TOUT SE COMPILE PARFAITEMENT !


    que dois je faire ... MERCI !

    Avis aux solutions ... ???

    Voici un appercu de l'interface :

  2. #2
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Je te conseil vivement la lecture de ce tutoriel qui me semble correspondre à ta problématique :
    Threads et performance avec Swing.
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  3. #3
    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,



    Ton problème vient de l'EDT !
    L'EDT (Event Dispatch Thread) est le thread qui s'occupe de gérer l'affichage et les evenements de l'interface graphique. C'est ce seul thread qui doit être utilisé lorsque tu modifies l'interface graphique. Et c'est également lui qui gère les évenements (clic de souris, clavier, etc) et les raffraichissements de l'affichage...

    Ce thread utilise une pile de traitement pour cela, mais s'il est bloqué par une tâche trop longue, ton interface sera figé...

    Dans ton cas la méthode actionPerformed() est appelée par ce thread puisqu'il s'agit d'un evenement. Tu peux vérifier cela avec la méthode SwingUtilities.isEventDispatchThread().

    Or comme tu fais le sleep() dans l'EDT, ce dernier ne peut pas mettre à jour l'affichage. Ainsi dans ton code :
    • Tu désactives tes boutons avec setEnabled(false) et tu changes ton icône, ce qui est bien fait au niveau de la mémoire mais pas de l'interface graphique. En réalité les composants "demandent" à l'EDT d'être redéssiné le plus tôt possible...
    • Tu bloques l'EDT avec le b]sleep()[/b] : aucun raffraichissement ne peux donc avoir lieu pendant ce temps...
    • Tu réactives tes boutons et restaures ton icône. Encore une fois les composants "demandent" à l'EDT d'être redéssiné...


    Une fois que ta méthode actionPerformed() est terminée, l'EDT peut reprendre ses tâches normales, et s'occupera donc de redéssiner les composants...

    l'état désactivé et l'icone orange associé ne seront donc jamais visible...


    En fait il faut que tu exécutes tes traitements dans un autre thread et de modifier l'interface avec SwingUtilities.invokeLater(). Mais le plus simple étant d'utiliser la classe SwingWorker.

    La classe SwingWorker a été introduite dans Java 6 en standard, mais il existe une version backport pour Java 5.0 (https://swingworker.dev.java.net/) 100% compatible et une vielle version dans les tutoriels de Sun (http://java.sun.com/products/jfc/tsc.../threads1.html).

    Cette dernière version est un peu moins complète (et ne possède pas les mêmes noms de méthodes) mais elle a l'avantage d'être compatible avec des JDK plus ancien...



    La classe SwingWorker propose principalement deux méthodes à surcharger :
    [list][*]doInBackground(), qui doit contenir le code à exécuter dans une tâche de fond (c-a-d dans un thread séparé).[*]done(), qui sera appelé par l'EDT une fois que la tâche sera terminé. Typiquement cette méthode permet de mettre à jours l'affichage après le traitement...


    Ainsi ta méthode actionPerformed devrait plus ressembler à ceci :
    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
    	public void actionPerformed (ActionEvent e)
    	{
    		if (e.getSource() == jButton1) {
    			// On est dans l'EDT, on modifie les attributs des composants :
    			jLabel42.setIcon(pause);	// j'affiche l'icone Pause (ORANGE)
    			jButton1.setEnabled(false);	// je désactive le premier bouton
    			jButton2.setEnabled(false);	// je désactive l'autre bouton
     
    			SwingWorker worker = new SwingWorker() {
     
    				// Ce traitement sera exécuté dans un autre thread :
    				protected Object doInBackground() throws Exception {
    					process.Stop("BS"); 		// je démarre le service BS
    					process.Attente(5000); 		// j'attends 5000 miliSec. (5sec) 
    					return null;
    				}
     
    				// Ce traitement sera exécuté à la fin dans l'EDT 
    				protected void done() {
    					// On est dans l'EDT, on restaure les attributs des composants :
    					jLabel42.setIcon(stop);		// j'affiche l'icone Stop (Rouge)	
    					jButton1.setEnabled(true);	// je Réactives les boutons
    					jButton2.setEnabled(true);	// je Réactives les boutons
    				}
    			};
     
    			// On lance l'exécution de la tâche:
    			worker.execute();
    		}
    	}

    Ainsi désormais ta méthode actionPerformed est très rapide (et ne bloque plus pendant 5 secondes) et redonne donc la main à l'EDT pour actualiser l'affichage de ton interface et gérer les autres évenements... Pendant que la méthode doInBackground() s'exécute dans un autre thread.


    La gestion des threads n'est pas forcément évidente à comprendre... mais avec Swing on peut dire qu'il y a deux règles simples :
    • Toutes les modifications sur les composants ou l'interface graphique doit être exécuté dans l'EDT.
    • Tous les traitements dans l'EDT doivent être rapide afin de ne pas le bloquer trop longtemps.



    Pour plus d'info sur le sujet, je te conseille de lire l'article de Romain Guy : Threads et performance avec Swing

    Si l'anglais ne te fait pas peur, tu peux jeter un coup d'oeil au tutoriel de Sun (mis à jours pour Java 6) : http://java.sun.com/docs/books/tutor.../dispatch.html

    Enfin, surveilles bien l'index de la section Java... mon petit doit me dit qu'un article sur le sujet ne devrait pas tarder


    a++


    PS : dernier détail, si tu n'utilises pas les flux d'entrée/sortie pour communiquer avec le process que tu lances, il vaut mieux les fermer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    cmd = Runtime.getRuntime().exec(new String [] {"net","stop", NomService,"/y"});
    cmd.getInputStream().close();
    cmd.getOutputStream().close();
    cmd.getErrorStream().close();
    PS 2 : Whoua j'ai encore posté un pavé... j'espère que cela te sera utile

  4. #4
    Membre averti
    Inscrit en
    Novembre 2006
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 31
    Par défaut
    Bonjour MAD_Tarik,

    Je suis loin d'être un crack car ça fait seulement deux mois que je programme en java. Et comme toi je me suis confronté à ce genre de problème.

    Tous les conseils que je trouvais étaient soit inefficaces (genre ajouter une méthode validate() ou repaint() ...) soit trop compliqué pour moi (genre gestion des thread ...).

    En faisant des essais tout seul comme un grand j'ai fini par tombé sur un truc qui marche. Mais peut être il ne faut pas le faire ???

    Si tu veux essayer, rajoute la ligne "this.update(this.getGraphics());" dans ta méthode "ActionPermormed" comme ceci :

    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
    public void actionPerformed (ActionEvent e)
            {
            ...
            if (e.getSource() == jButton1)
                {
                    jLabel42.setIcon(pause);    // j'affiche l'icone Pause (ORANGE)
                    process.Stop("BS");         // je démarre le service BS
                    jButton1.setEnabled(false);    // je désactive le premier bouton
                    jButton2.setEnabled(false);    // je désactive l'autre bouton
                    this.update(this.getGraphics());  // raffraichissement de l'interface
                    process.Attente(5000);         // j'attends 5000 miliSec. (5sec) 
                    jLabel42.setIcon(stop);        // j'affiche l'icone Stop (Rouge)    
                    jButton1.setEnabled(true);    // je Réactives les boutons
                    jButton2.setEnabled(true);    // je Réactives les boutons
            }
     
        ...
        }
    Normalement, ça marche bien.

  5. #5
    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
    Citation Envoyé par patanoc
    Normalement, ça marche bien.
    Pas tout à fait !
    Tu forces bien l'affichage de ta fenêtre, mais elle restera bloqué pendant les 5 secondes de pause qui suivent : tous les menus / bouton / effet de survol parraitront bloqués pendant ce temps... Pire tu peux te retrouver avec le bug du "rectangle-gris", c'est à dire que si une fenêtre vient se placer devant la tienne, alors elle ne sera plus affiché et se contentera d'une rectangle gris...

    Bref ton application ne sera pas très réactive !
    Lorsque tu developpes une application graphique, tu es obligé de gérer des threads pour les traitements "lourd"... et franchement ce n'est pas très dur d'utiliser SwingWorker...

    a++

  6. #6
    Membre averti
    Inscrit en
    Novembre 2006
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 31
    Par défaut
    adiGuba,

    Je comprends tout à fait ton point de vue.

    Maintenant, si le programme doit attendre 5 seconde, pourquoi premettre l'accès aux menus et boutons alors qu'il faut attendre 5 seconde avant de faire autre chose. Si l'utilisateur peut lancer une autre tache alors que le traitement long n'est pas fini, ça peut planter le programme car tout n'est pas dans un état stable.

    Pour le bug du rectangle gris, je n'était pas au courant. Mais la meilleure solution serait peut être de corrigé ce bug dans la bibliothèque SWING afin de nous simplifier le codage. Si ce bug ne peut pas être corrigé, c'est peut être que SWING a des gros défauts de conception à la base ???

    Comme je viens de débuter en java, j'ai sans doute tort d'écrire ces lignes mais j'aimerais bien comprendre pourquoi une ligne de code qui permet de régler un problème d'affichage ne devrait pas être utilisée au profit de solutions plus lourdes (pour éviter de dire dur).

    Merci d'avance en tous cas de tes éclaicissements !

    A+

  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
    Citation Envoyé par patanoc
    Maintenant, si le programme doit attendre 5 seconde, pourquoi premettre l'accès aux menus et boutons alors qu'il faut attendre 5 seconde avant de faire autre chose. Si l'utilisateur peut lancer une autre tache alors que le traitement long n'est pas fini, ça peut planter le programme car tout n'est pas dans un état stable.
    Je n'ai pas dit qu'il ne fallait pas désactiver certaines actions... mais de là à bloquer tout le programme il y a une marge !

    Ici l'attente de 5 secondes sert uniquement à modifier une icône et réactiver deux boutons, et je ne pense pas que l'utilisateur comprenne qu'il faille pour cela bloquer tout le programme (y compris menu, onglet, et zone de saisie).




    Citation Envoyé par patanoc
    Pour le bug du rectangle gris, je n'était pas au courant. Mais la meilleure solution serait peut être de corrigé ce bug dans la bibliothèque SWING afin de nous simplifier le codage. Si ce bug ne peut pas être corrigé, c'est peut être que SWING a des gros défauts de conception à la base ???
    Ce n'est pas un bug de Swing !!! C'est un bug de programmation !

    Depuis toujours Swing est mono-thread, et toute les modifications de l'interface doivent passé par l'EDT, alros que les traitements doivent être effectué dans des threads séparé. Si tu ne respectes pas cela il n'y a rien d'étonnant à avoir un bug !

    Pour info le même principe existe dans quasiment toutes les API graphique.

    Pour éviter cela il faudrait que tous les composants/classes soit thread-safe, ce qui compliquerait énormément la création de composant Swing !

    Toutefois, le bug du "rectangle gris" est tellement répandu qu'il a été en partie pris en charge avec Java 6 : au lieu d'afficher un rechtangle gris, c'est le dernier état de l'application qui est affiché, mais logiquement cela ne change en rien le fait que l'application soit quand même bloqué...

    Citation Envoyé par patanoc
    Comme je viens de débuter en java, j'ai sans doute tort d'écrire ces lignes mais j'aimerais bien comprendre pourquoi une ligne de code qui permet de régler un problème d'affichage ne devrait pas être utilisée au profit de solutions plus lourdes (pour éviter de dire dur).
    Tout simplement parce que l'interface graphique restera figé pendant tout le traitement, donc ici pendant 5 secondes, et qu'une application ne devrait pas se permettre de tel latence !

    Puisque tu débutes il vaudrait mieux en profiter pour coder quelque chose de propre plutôt que d'utiliser des "rustines" pour donner un faux-semblant de résultat correcte...


    Et l'utilisation de SwingWorker n'est pas vraiment beaucoup plus dur !


    a++

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

Discussions similaires

  1. Problème avec fonction sleep
    Par pitxu dans le forum Apache
    Réponses: 2
    Dernier message: 07/02/2008, 04h27
  2. problème sur un sleep
    Par dr4g0n dans le forum Linux
    Réponses: 3
    Dernier message: 22/01/2008, 22h00
  3. Problème avec fonction Sleep
    Par Evens dans le forum C++
    Réponses: 2
    Dernier message: 28/11/2007, 15h14
  4. [Débutant] Problème de corrélation entre deux vecteurs vitesses
    Par sydneya dans le forum Signal
    Réponses: 2
    Dernier message: 29/08/2007, 09h08
  5. Problème de pause dans un clip
    Par jeanfly dans le forum Flash
    Réponses: 6
    Dernier message: 04/05/2007, 15h23

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