java - Swing:滚动到 JScrollPane 的底部,以当前视口(viewport)位置为条件

标签 java user-interface swing jscrollpane

我试图模仿 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());
}

现在,这行得通了,但由于两个原因,它有点卡顿且不理想。

  1. 通过设置插入符位置,用户在聊天区域中的任何选择都将被删除。我可以想象,如果他试图复制/粘贴,这会非常恼人。
  2. 由于滚动 Pane 的推进发生在插入文本之后,所以有一瞬间滚动条处于错误的位置,然后它在视觉上跳向末尾。这并不理想。

在你问之前,是的,我已经阅读了关于 Text Area Scrolling 的这篇博文。 ,但默认的滚动到底部行为不是我想要的。

其他相关(但在我看来,在这方面并不完全有帮助)的问题: Setting scroll bar on a jscrollpane Making a JScrollPane automatically scroll all the way down.

在这方面的任何帮助将不胜感激。

编辑:

根据 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。

最佳答案

看看 scrollRectToVisible(Rectangle r)modelToView(int pos)

这应该可以在不影响用户选择的情况下为您提供所需的内容。

至于滚动条,尝试强制滚动和追加发生在不同的事件上。例如:

if (atBottom) {
    // append new line & do scroll
    SwingUtilities.invokerLater(new Runnable(){
        public void run() {
            // append text
        }});
} else {
    // append newline
    // append text
}

关于java - Swing:滚动到 JScrollPane 的底部,以当前视口(viewport)位置为条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2670124/

相关文章:

java - 可显示的 Toast 数量有限制吗?

Java Swing : Resizing JPanel with Image

java - 框架中面板的固定尺寸

java - 如何在 JFileChooser 中监听 'File Name' TextField 的变化?

java - 如何为类成员使用 .setTimeZone?

Java 子串增量

java - 正则表达式匹配变量声明

java - io.prometheus.client.Gauge 是否可用于线程安全计数器

ios - 如何在标题中制作搜索栏?

java - 尝试只允许在 JTextField 中输入数字,非数字设置为 0