自动文本滚动功能用于文本区域(JTextArea),光标位置设置为最后一行开头

15

我有一个简单的Java问题。我想要自动将文本滚动到使用JTextArea创建的文本区域的最后一行开头。文本区域每行的文本量相当长,超过了文本区域的宽度。

这是我用来设置的代码片段。

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

现在的问题是,使用上面的代码,默认行为是将插入符自动定位到文档末尾,结果导致整个文本区域的开始部分超出了范围。我希望自动滚动发生在文档最后一行的开头。

为了清楚起见,这里有两张屏幕截图,

我想要的是第一张,但实际发生的是第二张。

我想要的是这个 我得到的是这个

1个回答

14

更新文本区域的文本后,使用getLineCountgetLineStartOffset将插入符移动到正确位置。

以下是一个演示您期望的行为的工作示例:

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

}

很棒的解决方案!但我这里有一个问题。是否有任何方法可以仅设置ta.setCaretPosition(ta.getLineStartOffset(ta.getLineCount()-1))一次,而不是每次更新它,以便它在整个应用程序中保持有效? - SSaikia_JtheRocker
此外,即使您使用了DefaultCaret caret = (DefaultCaret) ta.getCaret();caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);这些语句,您的代码也可以正常工作吗?您对此有何看法? - SSaikia_JtheRocker
@JtheRocker 我不知道。由于文本更新时插入符号位置会不断移动,因此每次都需要重新计算其位置。您可以扩展JTextArea并覆盖setText方法,首先调用super.setText,然后定位插入符号。至于您的第二个问题,这是关于期望行为和人机工效学的问题。在您的问题中,这就是您所要求的。现在,如果您想要实际滚动到滚动窗格的左下角,则需要寻找其他解决方案。如果是这样,请考虑在SO上发布另一个问题。 - Guillaume Polet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接