2010-04-26 16 views
1

J'ai un code qui prend quelques minutes à traiter, il doit se connecter au web pour chaque chaîne dans un tableau long, chaque chaîne est une URL. Je veux faire en sorte que chaque fois qu'il se connecte, il doit actualiser la zone jtext afin que l'utilisateur ne regarde pas dans une page blanche qui semble figée pendant 20 min. ou si longtemps que cela prend. voici un exemple de quelque chose que j'ai essayé et n'a pas fonctionné:Sortie vers jTextArea en temps réel

try { 
      ArrayList<String> myLinks = LinkParser.getmyLinksArray(jTextArea1.getText()); 
      for (String s : myLinks) { 
       jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n"); 
      } 
     } catch (IOException ex) { 
      JOptionPane.showMessageDialog(jTextArea1, "Parsing Error", "Parsing Error", JOptionPane.ERROR_MESSAGE); 
      Logger.getLogger(MYView.class.getName()).log(Level.SEVERE, null, ex); 
     } 

Répondre

10

Le problème est que vous devez effectuer le calcul de manière asynchrone. Vous devez créer un thread d'arrière-plan qui effectue le calcul, puis utiliser SwingUtilities.invokeLater pour mettre à jour le JTextArea.

 
final ArrayList<String> myLinks = //... 
(new Thread() 
{ 
    public void run(){ 
     for (String s : myLinks) { 
      try{ 
       final String result = LinkChecker.checkFileStatus(s) + "\n"; 
       SwingUtilities.invokeLater(new Runnable(){ 
        public void run(){  
         jtextArea2.append(result); 
        } 
       }); 
      }catch(IOException error){ 
       // handle error 
      } 
     } 
    } 
}).start(); 

Modifier
Il a été souligné que la fonction append de JTextArea est en fait thread-safe (contrairement à la plupart des fonctions Swing). Par conséquent, pour ce cas particulier, il n'est pas nécessaire de le mettre à jour via invokeLater. Cependant, vous devriez faire encore vous traiter dans un thread d'arrière-plan de manière à permettre l'interface de mise à jour, de sorte que le code est:

 
final ArrayList<String> myLinks = //... 
(new Thread() 
{ 
    public void run(){ 
     for (String s : myLinks) { 
      try{ 
       jtextArea2.append(LinkChecker.checkFileStatus(s) + "\n"); 
      }catch(IOException error){ 
       // handle error 
      } 
     } 
    } 
}).start(); 

Cependant, pour à peu près toute autre opération qui modifie un objet Swing, vous aurez besoin utiliser invokeLater (pour s'assurer que la modification se produit dans le thread graphique), puisque presque toutes les fonctions Swing ne sont pas thread-safe.

+0

Merci, j'ai tout en place, mais il me dit que les s doivent être finales, donc il devrait être à la place (final String s: mylinks) à la place? –

+0

Pour l'exemple ci-dessus, myLinks doit être définitif. –

+0

Mais si vous avez la boucle forcée en dehors du Thread, alors vous devrez faire s final (créer fs final = s, et utiliser fs). –

0

Swing/AWT est une seule bibliothèque threadées, une fois un composant est montré, juste changer son apparence ne fonctionnera pas correctement. Vous devez changer le composant sur le thread graphique, pas à partir de votre thread. Pour ce faire wrap tout code qui met à jour un composant avec SwingUtilities.invokeLater ... comme dans

SwingUtilities.invokeLater(new Runnable() 
{ 
    public void run() 
    { 
     jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n"); 
    } 
}); 

aussi vous voulez limiter ce que vous faites sur le fil pour éviter l'IUG IUG de devenir atone, donc si checkFileStatus est prendre du temps, l'exécuter en dehors de la méthode d'exécution et stocker le résultat dans une variable locale finale, et accéder à la variable dans le code run().

+0

Ok, merci, je vais essayer maintenant :-) –

+0

dans quel paquet se trouve SwingUtils? –

+0

désolé javax.swing.SwingUtilities – MeBigFatGuy

1

Vous devez rechercher le filetage et son relationship to GUI updates dans Swing. Tout ce qui affecte ou utilise les composants de l'interface graphique dans Swing doit être fait sur un thread spécial appelé Event Dispatch Thread (EDT).

Si votre extrait de code, s'il gèle l'interface graphique, j'imagine qu'il est exécuté dans l'EDT. L'exécution d'une action de longue durée sur l'EDT rendra l'interface utilisateur inactive, car aucune autre mise à jour ne peut être effectuée pendant que votre processus de longue durée utilise le thread.

Il existe une classe auxiliaire appelée SwingWorker qui vous permet de décharger des calculs de longue durée sur un thread d'arrière-plan, puis de mettre à jour le thread graphique lorsque celui-ci est terminé. Le SwingWorker surveille le contexte bascule entre le thread graphique et le thread d'arrière-plan. Vous pouvez également afficher les barres de progression pour informer l'utilisateur de l'état du processus en cours, afin qu'il sache que votre application n'a pas été bloquée.

+0

Merci. Les réponses ci-dessus l'ont fait pour que je puisse le faire fonctionner maintenant, mais je pense que pour le long terme je devrais regarder ceci et comprendre comment cela fonctionne. –