Java / Swing : JTextArea dans un JScrollPane, comment empêcher le défilement automatique?

voici un exécutable morceau de code qui montre ce que mon "problème" est.

J'ai un JTextArea enveloppé dans un JScrollPane. Lorsque je modifie le texte de la JTextArea, le JScrollPane défile automatiquement à la fin du texte, et je n'en veux pas.

Voici mes exigences:

  • l'application ne devrait pas faire défiler verticalement automatiquement mais...
  • l'utilisateur devrait être en mesure de faire défiler verticalement
  • l'utilisateur ne devrait pas être en mesure de faire défiler horizontalement
  • l'application ne doit jamais défiler horizontalement
  • le JTextArea ne doit pas être modifiable

(donc même si il n'y a plus de texte que ce qui peut tenir à l'horizontale, ni l'application, ni l'utilisateur doit être en mesure de faire défiler horizontalement. Alors que verticalement, l'utilisateur doit être en mesure de les faire défiler.)

Je ne sais pas comment "réparer" ce, faut-il être fixé à l'aide de JTextArea ou JScrollPane méthodes?

Noter que AFAICT c'est pas une double exemplaire à tous: JTextPane empêche de défilement dans le parent JScrollPane

Voici le marrant exemple, toutes les 200 ms, il met le nouveau texte dans le JTextArea et vous pouvez voir la JScrollPane toujours défiler automatiquement à la fin du texte.

import javax.swing.*;
import java.awt.*;
import java.util.Random;
public final class TextInScrollPane extends JFrame {
private static final Random r = new Random( 42 );
public static void main( final String[] args ) {
final JFrame f = new JFrame();
f.setDefaultCloseOperation( EXIT_ON_CLOSE );
f.setLayout(new BorderLayout());
final JTextArea jta = new JTextArea( "Some text", 30, 30 );
jta.setEditable( false );   //This must not be editable
final JScrollPane jsp = new JScrollPane( jta );
jsp.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
jsp.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS );
f.add( jsp, BorderLayout.CENTER );
f.pack();
f.setLocationRelativeTo( null );
f.setVisible(true);
final Thread t = new Thread( new Runnable() {
public void run() {
while ( true ) { 
try {Thread.sleep( 200 );} catch ( InterruptedException e ) {}
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < 50 + r.nextInt( 75 ); i++) {
for (int j = 0; j < r.nextInt(120); j++) {
sb.append( (char) 'a' + r.nextInt(26) );
}
sb.append( '\n' );
}
SwingUtilities.invokeLater( new Runnable() {
public void run() {
jta.setText( sb.toString() );
}
} );
}
}
});
t.start();
}
}
note à tous: commentaires sur le vide catch bloc et de l'utilisation de final peut être envoyé à /dev/null, c'est vraiment pas ce que cette question est sur 😉

OriginalL'auteur SyntaxT3rr0r | 2010-10-19