如何仅在滚动条位于底部并且滚动锁定关闭时才使JTextPane自动滚动?

Fra*_*ick 10 java swing

如何仅在滚动条位于底部并且滚动锁定关闭时才使JTextPane自动滚动?这不应该与插入符号有任何关系,这似乎是我在Google上发现的.:(

Mik*_*ark 13

我认为我的程序完全符合您的要求,但有一个可能的警告:您不能输入文本区域.所以这对日志查看器很有用,但不适合交互式控制台.代码运行了一段时间,因为我已经把它变成了一个可以运行的方法演示.我建议按原样运行程序并检查行为.如果这种行为对您有用,那么请花一点时间研究代码.我在代码中包含了注释,以突出显示一些更重要的部分.


更新2013-07-17:您可能还希望在页面的下方单独回答中查看随机花花公子的解决方案.他的方法比我的更优雅.

另请参阅Swing:滚动到JScrollPane的底部,以当前视口位置条件,以获得不会干扰插入位置的潜在解决方案.


SCCE源代码如下:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Timer;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

public class ScrollingJTextAreaExample extends JFrame {
    // Worker thread to help periodically append example messages to JTextArea
    Timer timer = new Timer();
    // Merely informative counter, will be displayed with the example messages
    int messageCounter = 0;
    // GUI components
    JScrollPane jScrollPane;
    JTextArea jTextArea;

    public ScrollingJTextAreaExample() {
        initComponents(); // Boiler plate GUI construction and layout

        // Configure JTextArea to not update the cursor position after
        // inserting or appending text to the JTextArea. This disables the
        // JTextArea's usual behavior of scrolling automatically whenever
        // inserting or appending text into the JTextArea: we want scrolling
        // to only occur at our discretion, not blindly. NOTE that this
        // breaks normal typing into the JTextArea. This approach assumes
        // that all updates to the ScrollingJTextArea are programmatic.
        DefaultCaret caret = (DefaultCaret) jTextArea.getCaret();
        caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);

        // Schedule a task to periodically append example messages to jTextArea
        timer.schedule(new TextGeneratorTask(), 250, 250);

        // This DocumentListener takes care of re-scrolling when appropriate
        Document document = jTextArea.getDocument();
        document.addDocumentListener(new ScrollingDocumentListener());
    }

    // Boring, vanilla GUI construction and layout code
    private void initComponents() {
        jScrollPane = new javax.swing.JScrollPane();
        jTextArea = new javax.swing.JTextArea();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jScrollPane.setViewportView(jTextArea);
        getContentPane().add(jScrollPane, java.awt.BorderLayout.CENTER);
        setSize(320, 240);
        setLocationRelativeTo(null);
    }

    // ScrollingDocumentListener takes care of re-scrolling when appropriate
    class ScrollingDocumentListener implements DocumentListener {
        public void changedUpdate(DocumentEvent e) {
            maybeScrollToBottom();
        }

        public void insertUpdate(DocumentEvent e) {
            maybeScrollToBottom();
        }

        public void removeUpdate(DocumentEvent e) {
            maybeScrollToBottom();
        }

        private void maybeScrollToBottom() {
            JScrollBar scrollBar = jScrollPane.getVerticalScrollBar();
            boolean scrollBarAtBottom = isScrollBarFullyExtended(scrollBar);
            boolean scrollLock = Toolkit.getDefaultToolkit()
                    .getLockingKeyState(KeyEvent.VK_SCROLL_LOCK);
            if (scrollBarAtBottom && !scrollLock) {
                // Push the call to "scrollToBottom" back TWO PLACES on the
                // AWT-EDT queue so that it runs *after* Swing has had an
                // opportunity to "react" to the appending of new text:
                // this ensures that we "scrollToBottom" only after a new
                // bottom has been recalculated during the natural
                // revalidation of the GUI that occurs after having
                // appending new text to the JTextArea.
                EventQueue.invokeLater(new Runnable() {
                    public void run() {
                        EventQueue.invokeLater(new Runnable() {
                            public void run() {
                                scrollToBottom(jTextArea);
                            }
                        });
                    }
                });
            }
        }
    }

    class TextGeneratorTask extends TimerTask {
        public void run() {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    String message = (++messageCounter)
                            + " Lorem ipsum dolor sit amet, consectetur"
                            + " adipisicing elit, sed do eiusmod tempor"
                            + " incididunt ut labore et dolore magna aliqua.\n";
                    jTextArea.append(message);
                }
            });
        }
    }

    public static boolean isScrollBarFullyExtended(JScrollBar vScrollBar) {
        BoundedRangeModel model = vScrollBar.getModel();
        return (model.getExtent() + model.getValue()) == model.getMaximum();
    }

    public static void scrollToBottom(JComponent component) {
        Rectangle visibleRect = component.getVisibleRect();
        visibleRect.y = component.getHeight() - visibleRect.height;
        component.scrollRectToVisible(visibleRect);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ScrollingJTextAreaExample().setVisible(true);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)


ran*_*ude 10

这个问题迟到了,但我提出了这个解决方案.

  conversationPane = new JTextPane();
  final JScrollPane conversationScrollPane = new JScrollPane(conversationPane);
  conversationScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {

     BoundedRangeModel brm = conversationScrollPane.getVerticalScrollBar().getModel();
     boolean wasAtBottom = true;

     public void adjustmentValueChanged(AdjustmentEvent e) {
        if (!brm.getValueIsAdjusting()) {
           if (wasAtBottom)
              brm.setValue(brm.getMaximum());
        } else
           wasAtBottom = ((brm.getValue() + brm.getExtent()) == brm.getMaximum());

     }
  });   
Run Code Online (Sandbox Code Playgroud)

似乎完全符合我的需求.一点解释:基本上如果滚动条没有被人移动而且条形图最后一个/最低位置,则将其重置为最大值.如果正在手动调整,请检查它是否已调整到底部.


cam*_*ckr 3

文本区域滚动可能令人感兴趣。

我不知道滚动锁定键如何影响它。我在Scroll Lock的维基百科页面上找到了以下内容:

因此,Scroll Lock 可以被视为几乎所有现代程序和操作系统中已失效的功能。

所以我不会担心。