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

Composants Java Discussion :

JTextArea refresh et autoscroll


Sujet :

Composants Java

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 584
    Points : 181
    Points
    181
    Par défaut JTextArea refresh et autoscroll
    Bonjour,
    je suis entrain de développer l'IHM d'un petit programme.
    Dans ma fenêtre j'ai un bouton qui lance un long traitement.
    J'ai donc ajouté un JtextArea à ma fenêtre pour faire une sorte de console, et y écrire l'état du traitement en cours.

    Mais cette console me pose deux problèmes.

    1) Afin d'écrire et de mettre à jour la zone j'ai écrit la fonction suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    private static void log(String message) {
    	String text = MainFrame.logArea.getText();
    	MainFrame.logArea.setText(text + "\n" + message);
    	MainFrame.logArea.setCaretPosition(MainFrame.logArea.getText().length() - 1);
    	MainFrame.logArea.update(MainFrame.logArea.getGraphics());
    }
    Mais le update n'est pas très fluide, il fait clignoter la zone de texte.
    Dois-je passer par un thread pour supprimer ces scintillements ?

    2) Malgré la ligne suivante, la zone de texte ne sroll pas automatiquement, sauf à la fin du traitement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MainFrame.logArea.setCaretPosition(MainFrame.logArea.getText().length() - 1);
    j'ai essayé en déclarant mon champ ainsi, mais toujours pareil :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    DefaultCaret caret = (DefaultCaret) logArea.getCaret();
    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
    Comment faire pour afficher les dernières lignes ?

    D'avance merci pour vos réponses,

    Bebuck.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Tu ne dois pas appeler update, le textarea se redessine de lui même quand son texte change.
    Le scroll devrait fonctionner correctement avec ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MainFrame.logArea.setCaretPosition(MainFrame.logArea.getDocument().getLength());
    Ta méthode log est bien appelée depuis l'EDT?

    Note: pour éviter de refaire tout le textarea à chaque ligne, tu peux utiliser la méthode insertString sur son Document.

    Je suis surpris que ça scrolle à la fin du traitement. Tu ne serais pas occupé de bloquer ton EDT par un traitement long ? Ce qui rendrait tout opération graphique impossible puisque le thread chargé du dessin est bloqué.

  3. #3
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 584
    Points : 181
    Points
    181
    Par défaut
    Merci de votre réponse.
    Alors actuellement la fonction log n'est pas appelé depuis l'EBT, j'ai aucune gestion de thread manuelle.
    Je lance l'ihm, en appuyant sur les boutons je lance une fonction qui fait le traitement assez long, et c'est depuis cette méthode que je fais mes textArea.setText("toto");

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public static void initialization() throws IOException {
    	log("Début de l'initialisation"); // Affichage dans ma console
    	File tmpDirectory = new File(Utils.TEMP_PATH);
    	if (!tmpDirectory.exists()) {
    		tmpDirectory.mkdirs();
    	}
     
    	log("Fin de l'initialisation");
    }
    J'ai essayé de changer ma fonction log comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    private static void log(final String message) {
    	SwingUtilities.invokeLater(new Runnable(){
    		  public void run(){
    			  MainFrame.logArea.append( message );
    			  MainFrame.logArea.setCaretPosition(MainFrame.logArea.getText().length() - 1);
    		  }
    	});
    }
    Mais je voulais éviter de lancer un thread à chaque fois, et sans le update la zne de texte ne se met pas à jour, et avec le update, j'ai toujours mes scintillement

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Si ta méthode initialization() est lancée depuis un bouton, un menu ou n'importe quel autre composant d'UI AWT/Swing (via un ActionListener par exemple), alors elle s'exécutera dans l'Event Dispatch Thread, et donc l'UI ne se mettra à jour qu'à la fin de son exécution (de initialization()). Ce qui signifie que tes messages "logués" ne seront visibles qu'à la fin de l'exécution de cette méthode. Le fait de faire un SwingUtilises.invokeLater depuis cette méthode n'y changera rien.
    Il faut plutôt exécuter initialization() dans un thread autre que l'EDT (par exemple, en utilisant un SwingWorker), et mettre à jour le JTextArea dans l'EDT.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 584
    Points : 181
    Points
    181
    Par défaut
    Merci pour cette réponse,
    je vais me faire haïr de mon ancien architecte, mais j'espérais ne pas avoir à passer par un SwingWorker.
    C'est un peu lourd à mettre en place

    Mais ça marche super bien.
    Il n'y a pas de secret, le swingWorder ça marche.

    Voila le code si ça peut aider quelqu'un.

    Listener du bouton :
    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
    private void scanButtonActionPerformed(java.awt.event.ActionEvent evt) throws Exception {
     
            this.jFileChooser1.setVisible(true);
            int retour = jFileChooser1.showOpenDialog(null);
            if(retour == jFileChooser1.APPROVE_OPTION){
            	Utils.PATH_MOVIES = jFileChooser1.getSelectedFile().getAbsolutePath();
     
            	launchWait();
     
            	SwingWorker worker = new SwingWorker() {
     
        			@Override
        			protected Object doInBackground() throws Exception {
        				Search.listerFolder();
    					return null;
        			}
        		};
            	worker.execute();
            	stopWait();
            }
     
            this.ko.setVisible(false);
            this.ok.setVisible(true);
        }

    et la fonction qui écrit dans la console (le JTextArea) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private static void log(final String message) {
    		SwingUtilities.invokeLater(new Runnable(){
    			  public void run(){
    				  MainFrame.logArea.append( message );
    				  MainFrame.logArea.append( "\n" );
    				  MainFrame.logArea.setCaretPosition(MainFrame.logArea.getText().length() - 1);
    			  }
    		});
    	}
    Voila merci de votre aide, une fois de plus très précieuse

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Pourquoi ton ancien architecte (?) devrait-il te haîr pour utiliser un SwingWorker pour faire une tâche longue ? C'est fait pour ça, pour ne pas bloquer l'UI pendant longtemps ! Et pourquoi ça serait lourd ? Dans ton code, il n'y a qu'une ligne dans le SwingWorker, on peut difficilement faire plus simple.
    Autre chose : ton SwingWorker ne produit rien...donc il pourait justement produire (en utilisant les méthodes publish() et process()) les logs (plus besoin de invokeLater pour afficher les logs). Mais, pour le coup, ça obligerait à avoir passer un callback à ta méthode de traitement (par ailleurs, ça la rendrait indépendante de l'UI de log, ce qui du point de vue architecture ne serait pas plus mal).

    En revanche, c'est quoi launchWait() et stopWait() exactement ? Parce que stopWait est exécuté "immédiatement" après launchWait et tout effet conséquent sur l'UI de launchWait annulé par stopWait n'aurait pas d'effet visible. Eventuellement, pour "bloquer" l'UI pendant l'exécution de la tâche, on peut faire un "setEnabled(false)" là où tu fais launchWait(), et faire le "setEnabled(true)" dans la méthode done() sur SwingWorker, pour restaurer l'état de l'UI.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 584
    Points : 181
    Points
    181
    Par défaut
    Il me haïrait si il lisait que j'avais pas envie d'utiliser un swingWorker
    Après effectivement dans le cas présent la mise en place est très simple, je pensais que ça allait être un peu plus complexe.
    Sinon StartWait masque des composants et affiche un gif d'attente, stopWait réaffiche les composants et masque le gif.
    Mais effectivement avec le swingWorker, ça n'a plus lieu d'être

  8. #8
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Bebuck Voir le message
    Mais effectivement avec le swingWorker, ça n'a plus lieu d'être
    On peut afficher une progression pour un SwingWorker : justement, comme c'est long, c'est tout à fait justifié. Les tutoriaux classiques présentent une progression en barre, mais on peut tout à fait faire une progression de type continue avec un gif animé. En l'occurance, justement, en mettant la fin dans la méthode done() comme j'ai dit dans mon précédent post, et non à la fin de la méthode de l'écouteur, ce qui, en effet, ne sert à rien (l'évenement se termine immédiatement et non pas quand le travail du SwingWorkder se termine).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  9. #9
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2011
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 584
    Points : 181
    Points
    181
    Par défaut
    Tout a fait d'accord.
    Je pense que je vais diviser la frame en deux. D'un côté le gif (qui disparaîtra grace au done du swingWorker) et de l'autre la console qui détaille la progression du traitement

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

Discussions similaires

  1. [JTextArea]changer dynamiquement le nombre de colonnes
    Par MrDuChnok dans le forum Composants
    Réponses: 9
    Dernier message: 27/04/2004, 13h31
  2. Refresh
    Par bluevelvet dans le forum Bases de données
    Réponses: 3
    Dernier message: 01/04/2004, 13h20
  3. Probleme de Refresh avec TQuery et DBGrid
    Par insoo dans le forum C++Builder
    Réponses: 7
    Dernier message: 25/11/2003, 17h20
  4. Réponses: 2
    Dernier message: 23/12/2002, 20h34
  5. Sortir d'un progamme qui boucle ou qui refresh
    Par mikevador02 dans le forum C
    Réponses: 12
    Dernier message: 14/12/2002, 09h38

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