Java / Swing: JTextArea em um JScrollPane, como impedir a rolagem automática?

aqui está um pedaço de código executável que mostra qual é o meu "problema".

eu tenho umaJTextArea envolto em umJScrollPane. Quando mudo o texto doJTextArea, aJScrollPane rola automaticamente para o final do texto e eu não quero isso.

Aqui estão os meus requisitos:

a aplicaçãonão deveria rolar verticalmente automaticamente, mas ...o usuáriodevemos poder rolar verticalmenteo usuárionão deveria poder rolar horizontalmentea aplicaçãonunca deveria rolar horizontalmenteo JTextArea não deve ser editável

(portanto, mesmo que haja mais texto do que o que pode caber horizontalmente, nem o aplicativo nem o usuário poderão rolar horizontalmente. Enquanto na vertical, apenas o usuário deve rolar.)

Não sei como "consertar" isso: isso deve ser corrigido usandoJTextArea ouJScrollPane métodos?

Observe que AFAICT énão uma duplicata em todos os:JTextPane impede a rolagem no JScrollPane pai

Aqui está um exemplo meio engraçado: a cada 200 ms, ele coloca um novo texto noJTextArea e você pode ver oJScrollPane sempre rolando automaticamente para o final do texto.

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();
    }

}

questionAnswers(3)

yourAnswerToTheQuestion