我试图模仿Adium和我见过的大多数其他聊天客户端的功能,其中当新消息进入时滚动条会向前移动,但前提是你已经在那里.换句话说,如果您向上滚动了几行并正在阅读,当有新消息进入时它不会将您的位置跳到屏幕底部; 这会很烦人.但是如果您滚动到底部,程序会正确地假设您希望始终查看最新的消息,因此会相应地自动滚动.
我有一段时间试图模仿这个; 该平台似乎不惜一切代价来对抗这种行为.我能做的最好的事情如下:
在构造函数中:
JTextArea chatArea = new JTextArea();
JScrollPane chatAreaScrollPane = new JScrollPane(chatArea);
// We will manually handle advancing chat window
DefaultCaret caret = (DefaultCaret) chatArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
Run Code Online (Sandbox Code Playgroud)
在处理新文本的方法中:
boolean atBottom = isViewAtBottom();
// Append the text using styles etc to the chatArea
if (atBottom) {
scrollViewportToBottom();
}
public boolean isAtBottom() {
// Is the last line of text the last line of text visible?
Adjustable sb = chatAreaScrollPane.getVerticalScrollBar();
int val = sb.getValue();
int lowest = val + sb.getVisibleAmount(); …Run Code Online (Sandbox Code Playgroud) 我有一个JSCrollPane,其中JTextArea设置为其视图端口.
我连续更新JTextArea上显示的(多行)文本大约每秒一次.每次文本更新时,JScrollPane都会一直到文本的底部.
相反,我想弄清楚当前显示为原始文本中第一行的行号,并将该行作为文本更新后显示的第一行(或者如果新文本没有那么多行,然后一直滚动到底部).
我这样做的第一次尝试是获取当前插入位置,根据该位置计算线条,然后设置文本区域以显示该行:
int currentPos = textArea.getCaretPosition();
int currentLine = 0;
try {
for(int i = 0; i < textArea.getLineCount(); i++) {
if((currentPos >= textArea.getLineStartOffset(i)) && (currentPos < gameStateTextArea.getLineEndOffset(i))) {
currentLine = i;
break;
}
}
} catch(Exception e) { }
textArea.setText(text);
int newLine = Math.min(currentLine, textArea.getLineCount());
int newOffset = 0;
try {
newOffset = textArea.getLineStartOffset(newLine);
} catch(Exception e) { }
textArea.setCaretPosition(newOffset);
Run Code Online (Sandbox Code Playgroud)
这几乎可以满足我的需求,但要求用户在文本区域内单击以更改插入位置,以便滚动将保持状态(这不是很好).
我如何使用(垂直)滚动位置来代替?