Я пытаюсь подражать функциональности 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());
}
Теперь, это работает, но оно janky и не идеально по двум причинам.
- Устанавливая позицию каретки, любой выбор, который пользователь может иметь в области чата, стирается. Я могу себе представить, что это будет очень раздражать, если он попытается скопировать/вставить.
- Так как продвижение области прокрутки происходит после ввода текста, есть секунда, в которой полоса прокрутки находится в неправильном положении, а затем она визуально перескакивает к концу. Это не идеально.
Прежде чем спросить, да, я прочитал этот пост в блоге Прокрутка текстовой области, но поведение прокрутки по умолчанию по умолчанию - это не то, что Я хочу.
Другие связанные (но, на мой взгляд, не совсем полезные в этом отношении) вопросы: Настройка полосы прокрутки в jscrollpane Автоматическая прокрутка JScrollPane до конца.
Любая помощь в этом отношении будет очень оценена.
Edit:
В соответствии с рекомендациями 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.