我试图模仿 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);
在处理传入新文本的方法中:
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();
int maxVal = sb.getMaximum();
boolean atBottom = maxVal == lowest;
return atBottom;
}
private void scrollToBottom() {
chatArea.setCaretPosition(chatArea.getDocument().getLength());
}
现在,这可行,但由于两个原因,它很笨拙且不理想。
- 通过设置插入符号位置,用户在聊天区域中可能进行的任何选择都会被删除。我可以想象,如果他试图复制/粘贴,这将非常令人恼火。
- 由于滚动窗格的前进是在插入文本之后发生的,所以会有一瞬间滚动条处于错误的位置,然后它会在视觉上跳到最后。这并不理想。
在你问之前,是的,我已经阅读了关于Text Area Scrolling的这篇博文,但默认的滚动到底部行为并不是我想要的。
其他相关(但在我看来,在这方面并不完全有帮助)问题: 在 jscrollpane 上设置滚动条 使 JScrollPane 自动向下滚动。
非常感谢这方面的任何帮助。
编辑:
根据 Devon_C_Miller 的建议,我有一种改进的滚动到底部的方法,解决了问题 #1。
private void scrollToBottom() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
int endPosition = chatArea.getDocument().getLength();
Rectangle bottom = chatArea.modelToView(endPosition);
chatArea.scrollRectToVisible(bottom);
}
catch (BadLocationException e) {
System.err.println("Could not scroll to " + e);
}
}
});
}
我仍然有问题#2。