JTextArea 仅在附加文本时滚动到底部
JTextArea scroll to bottom only if text is appended
我正在尝试创建一个 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
来实现吗?
作为一个简单(粗略)的概念证明...
这基本上是将 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<JTextComponent, DocumentListener> 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,您可以将其用于 "install" 和 "uninstall" 所需的支持
查看 Smart Scrolling。
如果滚动条在底部,那么随着文本的追加,您将看到新的文本。
如果用户滚动到其他位置,则视口将停留在那里,直到用户滚动回底部。
我正在尝试创建一个 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
来实现吗?
作为一个简单(粗略)的概念证明...
这基本上是将 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<JTextComponent, DocumentListener> 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,您可以将其用于 "install" 和 "uninstall" 所需的支持
查看 Smart Scrolling。
如果滚动条在底部,那么随着文本的追加,您将看到新的文本。
如果用户滚动到其他位置,则视口将停留在那里,直到用户滚动回底部。