仅当附加文本时,JTextArea才会滚动到底部

我正在尝试创建一个JTextArea ,每次将文本追加到该文本区域时,它都会滚动到底部。 否则,用户应该能够滚动顶部并查看上一条消息。 我用过这段代码:

 JTextArea terminalText = new JTextArea(); JPanel terminal = new JPanel(); terminal.setLayout(new BorderLayout()); add(terminal); //Adds the terminal to mother JPanel //I added scrollbar to my JTextArea JScrollPane scroll = new JScrollPane(terminalText); terminal.add(scroll, BorderLayout.CENTER); scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); scroll.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { e.getAdjustable().setValue(e.getAdjustable().getMaximum()); }}); 

到目前为止,每当我使用terminalText.append将某些内容添加到terminalText时,此代码似乎会使我的文本区域滚动到terminalText文本区域的底部。

但是,用户无法使用滚动条滚动到顶部以查看上一条消息。 有没有办法来解决这个问题? 我应该使用DocumentListener来实现这一目标吗?

查看智能滚动 。

如果滚动条位于底部,则随附文本,您将看到新文本。

如果用户滚动到不同的位置,则视口将保持在那里直到用户滚动回到底部。

作为简单(粗略)的概念certificate……

这基本上将DocumentListener添加到JTextArea和任何Document事件,使用setCaretPosition将插入符号移动到文档的末尾。

 import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; import java.util.WeakHashMap; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.JTextComponent; public class Test { public static void main(String[] args) { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JTextArea ta = new JTextArea(10, 20); ta.setWrapStyleWord(true); ta.setLineWrap(true); MoveToTheBottom.install(ta); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JScrollPane(ta)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); Timer timer = new Timer(500, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ta.append(new Date().toString() + "\n"); } }); timer.start(); } }); } public static class MoveToTheBottom implements DocumentListener { private static WeakHashMap registry = new WeakHashMap<>(25); private JTextComponent parent; protected MoveToTheBottom(JTextComponent parent) { this.parent = parent; parent.getDocument().addDocumentListener(this); } public static void install(JTextComponent parent) { MoveToTheBottom bottom = new MoveToTheBottom(parent); registry.put(parent, bottom); } public static void uninstall(JTextComponent parent) { DocumentListener listener = registry.remove(parent); if (listener != null) { parent.getDocument().removeDocumentListener(listener); } } @Override public void insertUpdate(DocumentEvent e) { parent.setCaretPosition(e.getDocument().getLength()); } @Override public void removeUpdate(DocumentEvent e) { parent.setCaretPosition(e.getDocument().getLength()); } @Override public void changedUpdate(DocumentEvent e) { parent.setCaretPosition(e.getDocument().getLength()); } } } 

该示例演示了一个可重用的API,您可以使用该API来“安装”和“卸载”支持