我正在尝试模仿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());
}
现在,这种方法虽然可行,但有两个问题不太理想:
- 通过设置插入符位置,将删除用户在聊天区域中可能有的任何选择内容。如果用户正在尝试复制/粘贴,这可能非常恼人。
- 由于滚动窗格的提升是在文本被插入后发生的,因此会出现滚动条位置错误的瞬间,然后它才会向最末端跳转。这不是一个理想的情况。
在你询问之前,是的我已经阅读过这篇关于文本区滚动的博客文章,但默认的滚动到底部行为并不是我想要的。
其他相关(但在我的看法中,对此没有完全帮助)的问题: 设置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。