2009-03-21 6 views
3

J'ai quelques milliers de lignes de code quelque part et je l'ai remarqué que mon JTextPane vacille quand je le mettre à jour trop .. je l'ai écrit une version simplifiée ici:vacillante de composant Swing lorsque mis à jour beaucoup

import java.awt.*; 
import javax.swing.*; 

public class Test 
{ 
    static JFrame f; 
    static JTextPane a; 
    static final String NL = "\n"; 

    public static void main(String... args) 
    { 
     EventQueue.invokeLater(new Runnable(){ 
     public void run() 
     { 
     f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setVisible(true); 
     f.setSize(400, 300); 
     f.setLocationRelativeTo(null); 

     a = new JTextPane(); 
     f.add(new JScrollPane(a)); 

     new Thread(new Runnable(){ 
      public void run() 
      { 
       int i = 0; 
       StringBuffer b = new StringBuffer(); 
       while(true) 
       { 
        b.append(++i+NL); 
        a.setText(b.toString()); 
        a.setCaretPosition(b.length()); 
        try{Thread.sleep(10);}catch(Exception e){} 
       } 
      } 
     }).start(); 
     } 
     }); 

    } 
} 

Ceci est pour une interface graphique de style terminal (cmd) component--

Je pense que je l'ai fait toutes les optimisations que je pouvais ici, y compris avoir \n comme une variable finale, donc il ne sera pas construit des centaines de fois. Cependant, le scintillement est perceptible et inacceptable. Après quelques minutes, le composant se fige complètement. Je dois mettre à jour le composant très rapidement, et le volet doit être déplacé vers le bas lorsqu'il est mis à jour.

Je pensais créer ma propre version de JTextPane à partir de zéro, mais j'aimerais voir si vous avez une solution plus simple.

+0

Pourquoi l'accent curieux sur le mot "experts"? Pensiez-vous que vous obtiendriez une meilleure réponse en nous insultant? –

+1

Désolé, aucune infraction prévue. Édité. – Bai

Répondre

8

Une partie de votre erreur est que vous accédez à un composant Swing depuis l'extérieur du fil d'événements! Oui, setText() est thread-safe, mais les méthodes Swing ne sont pas thread-safe à moins qu'ils ne soient explicitement déclarés comme tels. Par conséquent, setCaretPosition() n'est pas sécurisé au thread et doit être accessible à partir du thread d'événement. C'est presque certainement pourquoi votre application finit par geler.

REMARQUE: JTextPane hérite sa méthode setText() de JEditorPane et sa méthode setCaretPosition de JTextComponent, ce qui explique les liens dans le paragraphe précédent ne va pas à la page JTextPane JavaDoc.

Pour être de sécurité de cette discussion, vous avez vraiment besoin d'au moins appeler setCaretPosition() à partir du fil d'événements, que vous pouvez faire avec le code comme ceci:

SwingUtilities.invokeAndWait(new Runnable() { 
    public void run() { 
    a.setText(b.toString()); 
    a.setCaretPosition(b.length()); 
    } 
} 

Et puisque vous devez appeler setCaretPosition() à partir du thread de l'événement, vous pouvez aussi bien appeler le setText() du même endroit.

Il est possible que vous n'ayez pas besoin de régler manuellement la position du curseur. Consultez la section "Caret Changes" dans JavaDoc pour JTextComponent.

Enfin, vous pouvez consulter une série de deux articles:

+0

Je ne peux pas vraiment mettre tout cela dans l'EDT, parce que sleep() va l'engorger tellement que le composant gèlera complètement. – Bai

+1

Pas le sommeil! Mais setCaretPosition * doit * être dans l'EDT. Sinon, vous rencontrerez des blocages occasionnels (ou pas si occasionnels). – Eddie

+0

A v. Bonne réponse; juste besoin de ');' ajouter à la fin du code. –

1

Vous ne savez pas si cela fonctionnera, mais vous pouvez essayer d'utiliser la méthode insertString() de l'instance Document du volet de texte. J'essaierais d'avoir un seul espace à la fin du document et de garder le curseur positionné après cet espace; mais lorsque vous insérez une chaîne, insérez-la avant l'espace. De cette façon, la position du curseur restera automatiquement à la fin du document.

Je pense que le volet de texte pourrait être redessiné deux fois, une fois lorsque vous appelez setText() et une fois lorsque vous appelez setCaretPosition(), et que cela pourrait contribuer au scintillement. Pas sûr, cependant (cela fait un moment que j'ai travaillé avec Swing).

Questions connexes