如何仅在滚动条位于底部并且滚动锁定关闭时才使JTextPane自动滚动? [英] How to make JTextPane autoscroll only when scroll bar is at bottom and scroll lock is off?
问题描述
如果仅当滚动条位于底部并且滚动锁定关闭时,如何使JTextPane自动滚动?这不应该与插入符号有任何关系,这似乎是我在Google上发现的。 :(
How to make JTextPane autoscroll only when scroll bar is at bottom and scroll lock is off? This shouldn't have anything to do with caret, which is what I seem to be finding all over Google. :(
推荐答案
我认为我的程序完全符合您的要求,但有一个可能的警告:您不能输入这对于日志查看器来说是好事,但不是交互式控制台。代码运行时间有点长,因为我已经把它变成了一个可以随时运行的方法演示。我建议运行程序为 - 是的,检查行为。如果行为适合你,那么投入一点时间研究代码。我在代码中包含了注释,以突出一些更重要的部分。
I think my program below meets your requirements exactly, with one possible caveat: you're not allowed to type in the text area. So this would be good for a log viewer, but not an interactive console. The code runs a little long because I have made it into a ready-to-run demo of the approach. I suggest running the program as-is and checking out the behavior. If the behavior works well for you, then invest a little time in studying the code. I have included comments in the code to highlight some of the more important sections.
更新2013-07-17:您可能还希望在他的单独答案中查看 random dude 的解决方案。他的方法比我的方法更优雅。
Update 2013-07-17: You may also want to check out random dude's solution in his separate answer farther down the page. His approach is more elegant than mine.
另见 Swing:滚动到JScrollPane的底部,以当前视口位置为条件,以寻找不会干扰插入位置的潜在解决方案。
Also see Swing: Scroll to bottom of JScrollPane, conditional on current viewport location for a potential solution that does not interfere with the caret position.
SCCE来源代码如下:
SCCE source code follows:
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);
}
});
}
}
这篇关于如何仅在滚动条位于底部并且滚动锁定关闭时才使JTextPane自动滚动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!