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

Interfaces Graphiques en Java Discussion :

Une classe JProgressBar réutilisable


Sujet :

Interfaces Graphiques en Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut Une classe JProgressBar réutilisable
    Bonjour,
    Je suis sur un problème depuis plusieurs jours, et après avoir essayer plusieurs méthodes qui marchent mais ne me satisfassent pas entièrement, je me tourne vers vous !
    Mon but : avoir une classe qui étends JFrame, qui contiennent une JProgressBar et un JTextArea et surtout, surtout, qui soit réutilisable !

    Ce que j'ai fait :
    - une classe qui créé ma Jframe et qui contient des méthodes de setTitle, setTxtAppend pour mettre à jour le JTxtArea, setProgress pour mettre à jour la JProgressBar ... etc.
    - une action (boucle) lancée depuis l'EDT qui met à jour la JProgressBar selon la méthode définie ci-dessus.

    Avant ce que je faisais, c'était un update(getGraphics) sur ma JFrame pour mettre à jour la progressbar, ce qui marchait très bien, jusqu' à ce que je m'aperçoive que ça me rallongeai considérablement mon temps de traitement.

    J'ai donc essayé le SwingWorker, qui est génial mais qui ne me sert à rien puisque de toute manière je dois attendre la fin de mon traitement pour continuer. J'ai essayé des SwingUtilities.invokelater dans tous les sens, même des invokenadwait, mais rien n'y fait : pas de mise à jour.

    En fait, j'obtiens ce que je veux en faisant un progressbar.update(progressbar.getGraphics) mais le résultat est un peu "sale" : la barre clignote et ce n'est pas beau du tout (évidemment car en fait dans ce cas j'update la barre à chaque itérations)

    Donc ce que je ne comprends pas, c'est que je mets bien à jour ma progressbar dans l'edt puisque j'y suis (test à l'appui ), mais la barre ne se mets pas à jour, et je suis obligé de passer par un update(getGraphics) soit de la barre, soit de la frame qui contient la barre ( d'ailleurs c'est idem pour le panel qui contient la barre ! où l JRootPane qui contient le panel qui contient ... bref, vous avez compris )

  2. #2
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    après avoir lancé votre SwingWorker ou votre invokeLater, vous devez sortir de votre action pour que l'update se fasse.

    Non seulement update(getGraphics()) est sale mais il est surtout garanti de ne pas fonctionner avec tous les Toolkits, getGraphics() peux retourner null ou un Graphics non prêt à l'affichage.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    après avoir lancé votre SwingWorker ou votre invokeLater, vous devez sortir de votre action pour que l'update se fasse.
    Mais ce que je ne comprends pas, c'est d'une part pourquoi être obligé de faire un invokelater alors que je suis dans l'EDT, ce qui me rends mon processus complètement asynchrone de ma barre, et d'autre part, mon action est une boucle, donc si je sort de la boucle, je ne peux plus updater la barre ... à moins que j'aie mal compris ...
    Pourquoi avoir besoin de faire tout ça alors que je reste en séquentiel, dans l'EDT, donc ça ne devrait pas être si compliqué non ? c'est simplement dû au fait que je fais appel à une classe extérieure ?
    Peut être y a-t-il une façon plus simple de faire une progressbar un peu évoluée et réutilisable autre que dans une jframe, dans un dialog peut être ?
    Des idées ?
    Merci tchize

  4. #4
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    pour faire simple, tant que votre boucle squatte l'edt, celui-ci ne va plus lire les évènements de sa pile d'évènements. ceci aura les conséquence suivantes:

    1) plus aucun bouton votre application, plus aucun menu ne pourra réagir
    2) l'OS va voir que les pings dans la pile ne sont pas traité et va qualifier votre application de "ne répond pas"
    3) la fenetre ne se redessinera pas quand d'autre fenetre passeront au dessus, effet "rectangle gris".

    Le but est justement de forcer les opérations lourdes à avoir lieu "en dehors" de l'EDT. Mais les opération sur les composants, elles doivent avoir lieu dans l'EDT.

    C'est assez chiant à gérer, et SwingWorker est là pour ça

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    pour faire simple, tant que votre boucle squatte l'edt, celui-ci ne va plus lire les évènements de sa pile d'évènements. ceci aura les conséquence suivantes
    super, là j'ai très bien compris ... je crois !
    mais du coup, lorsque j'utilise swingworker, comme j'ai toute une suite de processus les uns à la suite des autres, du coup la mise à jour graphique, qui doit dépendre du résultat du premier processus, se fait plus vite que le processus lui même ! du coup j'avais cherché à synchroniser le swingworker et mon processus, ou alors à attendre que mon processus soit fini pour actualiser mes autres vues, mais sans succès ...

  6. #6
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    soit:

    tu envoie des informations via la méthode publish depuis "doInBackground'. SwingWorker va alors lancer dans l'EDT la méthode process() avec ces données, tu pourra y faire le nécessaire pour mettre à jour ton affichage.


    tu utilise la méthode simple "setProgress", swingworker invoquera alors les listener (ProgressListener) dans l'EDT, ce listener peuvent servir donc à mettre à jour l'affichage.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    soit:

    tu envoie des informations via la méthode publish depuis "doInBackground'. SwingWorker va alors lancer dans l'EDT la méthode process() avec ces données, tu pourra y faire le nécessaire pour mettre à jour ton affichage.


    tu utilise la méthode simple "setProgress", swingworker invoquera alors les listener (ProgressListener) dans l'EDT, ce listener peuvent servir donc à mettre à jour l'affichage.
    Pour l'affichage de ma barre, tout est ok, pas de soucis.
    Le problème c'est que je lance mon worker dans un processus qui modifie un objet. Les changements sur cet objet sont écoutés pour la mise à jour de la Gui. Pour résumer :
    - je lance mon processus qui fait des modification sur un objet
    - dans ce processus je lance mon worker qui va donc se dérouler en arrière plan
    - à la fin du processus mon objet est updaté, donc la vue qui le concerne mise à jour; pendant ce temps, comme le process du doinbackground n'est pas fini, la mise à jour finale se fait sur un objet donc on pourrai dire qu'il n'est "pas fini de modifier"

    J'avais donc tenté de bloquer mon EDT pour attendre la fin de mon worker (super logique tout ça ), et finalement abandonné car conceptuellement faux ! Comment je dois faire alors pour prévenir, faire attendre, mettre en pause le processus qui lance mon worker ?

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Tout dépend bien sur de l'architecture que vous visez, mais vous pouvez par exemple


    -> passer un runnable() à votre swing worker, que vous exécuteriez une fois le travail principal fini
    -> lancer un thread qui appel directement ou indirectement get() sur le swingworker (attention bloquant)
    -> Si c'est pour changer l'affichage une fois le travail de la proressbar fini:
    Faire du coté appelant aussi un swingworker qui, dans son doInBackground, va attendre que l'autre swingworker aie fini (méthode get()) et dans son done() met à jour l'affichage. Exemple:

    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
    public class MaProgressBar {
     
        // ne pas appeler depuis l'EDT!
        public String faireLeTravail(){
           SwingWorker<String,String> s = creerSwingWorker();
           s.execute();
           return s.get();
     
        }
    }
     
    public void actionButonPerformed(){
        new SwingWorker<String,String>(){
    	public String doInBackground() {
                return new MaProgressBar(tout,le,bordel).faireLeTravail();
            }
            public void done(){
                mettreAJourAffichage(get());
            }
        }.execute();
    }

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    oh la vache, ça devient super compliqué là
    autant pour le 1) que le 2), qui m'ont l'air plus simple que le 3) dont tu donnes un exemple, je ne vois pas trop comment faire ...
    ma classe qui lance mon processus qui fait appel à un worker implémente plein d'autres méthodes : ça m'embête un peu de la faire étendre swingworker ...
    et comme je fonctionne par observer / observable, la mise à jour se fait automatiquement à chaque changement ...

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    Voilà, c'est résolu !
    En fait comme je lançais mon processus via une JMenuBar, j'ai simplement rajouté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    new SwingWorker() {
      public Object doInBackground() {
        currentProjet.addListe();
        observableP.updateProjet(currentProjet);
        observableP.updateTreeProjet(currentProjet);
        return null;
      }
      public void done() {
        observableP.updateProjet(currentProjet);
        observableP.updateTreeProjet(currentProjet);				
      }
    }.execute();
    et tout fonctionne sur des roulettes, car je lance mon processus ET je fais mes updates DANS le SwingWorker.

    Mais franchement, j'ai trouvé ça plus ou moins au pif car je ne pensais pas qu'on pouvait appeler comme ça un SwingWorker, et je n'arrive toujours pas à saisir la logique complète du truc ... enfin, on verra plus tard
    Merci Tchize !

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    un swingworker n'est qu'un classe et le code que tu utilise là, ca crée une sous classe anonyme, l'instancie et appel exécute dessus

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    En fait ce que je comprends, c'est que dans ce que j'ai fais, j'ai tout mis en tâche de fond. Mais pourquoi ça ne pourrai pas marcher sur le même principe mais dans l'EDT ?

  13. #13
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    l'EDT est un système évenementiel qui pompe des instructions 'dessine ceci, fenetre bougée, curseur bougé, bouton cliqué etc', il ne peux donc pas être bloqué, donc on met tout le code "lourd" dehors.

    Maintenant, les objets swing ne sont pas threadsafe, on ne peux donc pas les modifier depuis une autre thread que l'EDT, doc les appel de type progressBar.setValue(), label.setText() etc doivent avoir lieu dans l'EDT.

    Ce pour jongler avec ça (mise à jour des composants et processus lourd) que swingworker est utilisé

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    ok !
    merci pour tout en tout cas !

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    Re !
    Maintenant j'ai un autre problème.
    Je travaille sur des listes de discussions, et mon problème précédent venait quand j'avais à extraire disons 50000 messages : il fallait que je fasse patienter mon utilisateur en beauté ! Bon, ça, c'est fait !
    Mon problème maintenant, c'est que lorsque je travaille sur 50000 messages, toutes mes opérations deviennent des processus longs : serialisation, déserialisation, mise à jour de modèle de JTable ... etc, et non plus seulement des calculs !
    Donc je me retrouve à mettre des SwingWorker partout !!
    Y aurait-il une solution plus "générique" ?

  16. #16
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    ben tu peux factoriser ton code pour éviter de mettre la meme logique à 50.000 endroits, mais il n'y a pas plus générique pour les traitements longs que swingworker

  17. #17
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 116
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    ben tu peux factoriser ton code pour éviter de mettre la meme logique à 50.000 endroits, mais il n'y a pas plus générique pour les traitements longs que swingworker
    Oui, merci
    Nan, en fait je vais changer quelques trucs, parce que ça a révélé des failles conceptuelles !!
    Merci et @+

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

Discussions similaires

  1. [cls et Vbs]réutilisation d'une classe écrite dans un autre fichier
    Par EvaristeGaloisBis dans le forum VBScript
    Réponses: 0
    Dernier message: 20/02/2015, 15h03
  2. Réutilisation d'une classe CSS dans une autre
    Par Colbix dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 22/09/2007, 22h37
  3. [Juridique] Comment réutiliser le code source d'une classe ?
    Par mathieu dans le forum Général Java
    Réponses: 8
    Dernier message: 17/05/2004, 13h40
  4. Variable d'une Classe Ancêtre
    Par Génie dans le forum Langage
    Réponses: 3
    Dernier message: 18/09/2002, 19h24
  5. Sortir un typedef d'une classe
    Par Theophil dans le forum C++Builder
    Réponses: 13
    Dernier message: 03/07/2002, 17h21

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