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 :

Question classique: faire un traitement longue durée sans bloquer l'affichage


Sujet :

EDT/SwingWorker Java

  1. #1
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut Question classique: faire un traitement longue durée sans bloquer l'affichage
    Bonjour,

    voici la situation:
    - mon application se déroule dans le fil principal AWT-EventQueue
    - lors d'un évènement (ActionEvent) par exemple ou lors de conditions particulières, ce fil d'exécution demande le lancement d'un traitement long, qui peut même se bloquer ( Téléchargement FTP par exemple, avec risque de perdre la communication ).
    - Évidemment ce processus sera exécuter dans une autre Thread.

    Attendu:
    - Le traitement longue durée doit montrer sa progression via l'interface graphique, par un barregraphe ou autre moyen d'afficher un pourcentage.
    - MAIS... le fil principal de l'application, doit attendre le résultat du traitement longue durée, pour décider de la suite des opérations
    - ET... le fil principal doit être capable de continuer tout seul, au bout d'une temporisation, au cas où le traitement longue durée ne donne plus signe de vie (par exemple il ne publie pas son état d'avancement, ce qui laisse supposer qu'il est bloqué).

    => donc le fil principal doit entrer dans une sorte de boucle d'attente:
    + attendre le retour normal de traitement
    + ou attendre la fin de la temporisation de sécurité.

    Problème:
    Faire une boucle d'attente à l'aide d'un Do-While, ou une attente du genre MonThreadTraitement.join(), cela provoque un blocage au niveau du fil principal AWT-EventQueue, et donc une absence de rafraîchissement graphique.

    J'ai beau tourner le problème dans tous les sens:
    - si je ne veux pas bloquer le rafraîchissement graphique, je ne peux alors pas faire la boucle d'attente, et donc je ne saurai jamais le résultat du traitement...
    - si je fais une boucle d'attente du résultat dans le fil principal, je n'aurai pas de rafraîchissement graphique.

    Je deviens fou


    -
    @ bientôt...

    Salut & @+ sur 3W!

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Swing a déjà ce qu'il faut pour des traitement de tache de fond grace a la classe javax.swing.Timer (voir didacticiel) ou encore javax.swing.SwingWorker même si on peu aussi utiliser des Thread ou ExecutorService de plus bas niveau (mais il faudra alors coder la tuyauterie).

    Pour faire des maj de l'UI il suffit d'invoquer SwingUtilities.invokeLater(). On peut donc faire remonter dans l'EDT ce qu'on veut (valeur de progression, résultat intermédiaire, etc.)
    Pour avoir des valeurs observables c'est en JavaFX qu'il faut faire mais dans ce cas on est plus dans Swing.

    Il n'est pas nécessaire de faire un do-while ou une attente puisque cela va bloquer AWT.
    En première approche, ce qu'il faut faire c'est rendre impossible la saisie utilisateur (ex: en désactivant les contrôles ou en mettant un glasspane qui intercepte les saisies souris)

    Après il est, par exemple, possible mettre en place un callback qui sera invoque une fois la tache réussie ou échouée.

    ex dans le corps de la tache :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    private Whatever onSuccess = null;
    // Setter / Getter
     
     
    // Long task in Timer or Thread.
    [...]
    // Success.
    Optional.ofNullable(getOnSuccess())
        .ifPresent(whatever-> SwingUtilities.invokeLater(() -> whatever.doSomethingAtEDTWhenTaskFinishesOK()));
    Depuis Java 6 on peut aussi utiliser javax.swing.SwingWorker (doc) qui offre une API de plus haut niveau pour les traitements asynchrones. Gérer l'annulation au bout d'un certain temps peut se faire via la méthode get(long timeout, TimeUnit unit) (voir la doc pour savoir comment créer une tache asynchrone avec cette classe). Les méthode process() et done() de cette classe sont exécutées dans l'EDT durant les mises a jour des valeurs et a la fin de la tache.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut
    Bonjour et merci bouye pour ces précisions.

    j'avais tenté du SwingUtilities.invokeLater() et du javax.swing.SwingWorker.
    Cependant cela ne se prêtait pas bien à mon cas de figure.
    C'est en relisant les tutos de ce site, ainsi que mon post que j'ai trouvé la solution:
    => Sortir tout le traitement de l'EDT.

    Il a fallu que je ré-adapte l'architecture du traitement mais le principe est simple:
    - L'utilisateur demande une action à travers un bouton par exemple... on est dans le fil de l'EDT
    - Cet évènement appelle une procédure du style AbstractAction... tout ce qui est dans cette portion de code, ainsi que toutes les procédures qui seront appelées via cette portion de code, seront encore traitées dans le fil de l'EDT. Et c'est là que se situe le problème !

    => Au lieu de lancer mon traitement longue durée depuis cet emplacement, je lance maintenant un appel à ce traitement via SwingUtilities.invokeLater()... et là, cela ne tournera plus dans le fil de l'EDT.

    Cà paraît tout bête dit comme cela, mais fallait trouver comment organiser ce système.

    Pour ceux qui serait confronté à un problème similaire, je conseille d'utiliser lors des débogages, des traceurs du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    System.out.println( Thread.currentThread().getName() + ": Lancement TacheTransfertData()..." );
    Ceci permet de voir dans quel fil (ou Thread) de traitement, le code est exécuté; ainsi les choses devraient s'éclaircir.
    En tout cas, cela m'a permis de résoudre mon problème.
    @ bientôt...

    Salut & @+ sur 3W!

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    N'importe quel code qui est invoqué via SwingUtilities.invokeLater() se déroule dans l'EDT et ne peut donc être considéré comme une tache de fond. Tu te contentes de demander à ce que ton action s'execute "plus tard" une fois que toutes les actions en attente sur l'EDT soient terminées, mais cela s'exécute quand même sur l'EDT. En cas de traitement vraiment long (connexion BD, chargement de grosses données, connexion réseau, etc.) le blocage de l'UI sera de nouveau apparent à l'utilisateur.

    Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 08/09/2006, 12h12
  2. Réponses: 18
    Dernier message: 22/06/2006, 17h55
  3. Réponses: 19
    Dernier message: 30/05/2006, 18h43
  4. Gettickcount longue durée
    Par BECHE dans le forum Langage
    Réponses: 3
    Dernier message: 06/12/2005, 23h01
  5. Afficher un message sans bloquer les autres traitements??
    Par Ben_Le_Cool dans le forum Langage
    Réponses: 7
    Dernier message: 13/10/2005, 00h21

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