Java / Swing: JTextArea в JScrollPane, как предотвратить автоматическую прокрутку?

Вот исполняемый фрагмент кода, который показывает мою «проблему».

у меня естьJTextArea завернутый вJScrollPane, Когда я изменяю текстJTextArea,JScrollPane прокручивает автоматически до конца текста, и я не хочу этого.

Вот мои требования:

приложениене следует прокручивать по вертикали автоматически, но ...Пользовательдолжен быть в состоянии прокрутить вертикальноПользовательне следует быть в состоянии прокрутить горизонтальноприложениеНикогда не следует прокрутить горизонтальноJTextArea не должен быть редактируемым

(поэтому, даже если текста больше, чем может поместиться по горизонтали, ни приложение, ни пользователь не должны иметь возможность прокручивать по горизонтали. Хотя по вертикали, прокручивать может только пользователь.)

Я не знаю, как «исправить» это: это должно быть исправлено с помощьюJTextArea или жеJScrollPane методы?

Обратите внимание, что AFAICT этоне дубликат на всех:JTextPane предотвращает прокрутку в родительском JScrollPane

Вот довольно забавный пример, каждые 200 мс он помещает новый текст вJTextArea и вы можете увидетьJScrollPane всегда прокручивать автоматически до конца текста.

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

}