Auto text scroll for text area (JTextArea) with caret position set to the beginning of the last line

SSaikia_JtheRocker picture SSaikia_JtheRocker · May 21, 2012 · Viewed 13.8k times · Source

I have a simple Java question here. I want to auto text scroll to the beginning of the last line of a text area created using JTextArea. The amount of text per line of the text area is quite longer than the width of the text area.

Here is the code snippet I used to set that up.

JTextArea textArea = new JTextArea();
DefaultCaret caret = (DefaultCaret)textArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

The problem now is, with the above code, the default behavior is that the caret is auto positioned to the end of the document, as a result, the beginning part of the whole text area gets out of scope. I'd prefer the auto scroll to happen to the beginning of the last line in the document.

To make it clear, here are two screen shots,

What I want is the first one but what's happening is the second one.

What I want is this What I get is this

Answer

Guillaume Polet picture Guillaume Polet · May 21, 2012

Simply move the caret to the correct location using getLineCount and getLineStartOffset after updating the text of the textarea.

Here is a working example illustrating your desired behaviour:

import java.util.List;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;

public class Test {

    private JFrame frame;
    private JTextArea ta;

    protected void initUI() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ta = new JTextArea();
        DefaultCaret caret = (DefaultCaret) ta.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
        frame.add(new JScrollPane(ta));
        frame.setSize(400, 200);
        frame.setVisible(true);
        new UpdateText().execute();
    }

    class UpdateText extends SwingWorker<String, String> {

        @Override
        public String doInBackground() {
            for (int i = 0; i < 1000; i++) {
                publish("Hello-" + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        public void process(List<String> chunks) {
            for (String s : chunks) {
                if (ta.getDocument().getLength() > 0) {
                    ta.append("\n");
                }
                ta.append(s);
            }
            try {
                ta.setCaretPosition(ta.getLineStartOffset(ta.getLineCount() - 1));
            } catch (BadLocationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        @Override
        public void done() {

        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Test().initUI();
            }
        });
    }

}