gpt4 book ai didi

java - 智能 JScrollPane 跟随输出文本

转载 作者:行者123 更新时间:2023-12-01 11:45:27 29 4
gpt4 key购买 nike

我有一个智能 JScrollPane,但与其他所有解决方案不同,我想知道如果滚动 Pane 不在底部并且文本是否可以跟随(向上滚动)查看的组件(JTextArea)缓冲区已满。包含功能齐全的代码片段。谢谢。

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;
MyJTextArea 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 MyJTextArea();
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. \n";
jTextArea.appendText(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);
}
});
}


public class MyJTextArea extends JTextArea {
DefaultCaret caret;
static final int BUFFERSIZE = 100;

public MyJTextArea() {
setBorder(BorderFactory.createEtchedBorder());
setBackground(Color.black);
setForeground(Color.white);
setCaretColor(getForeground());
setFont(new Font("Lucida Console", Font.PLAIN, 12));
setLineWrap(false);
setEditable(false);
}

public void appendText(String text) {
// When the line count in the text window > size of the buffer,
// replace the first line in buffer to give way to the last line,
// all lines in buffer shift one line up
if (getLineCount() > BUFFERSIZE) {
try {
replaceRange(null, getLineStartOffset(0), getLineEndOffset(0));
} catch (Exception e) {
append("An exception occured in replacing the topmost entry in the buffer");
e.printStackTrace();
return;
}
}
append(text);
}
}
}

最佳答案

在您的示例中,您有 100 行的缓冲区。假设打开滚动锁定时,视口(viewport)中的第一行位于第 40 行。

如果我理解您的要求,那么一旦您开始从文档中删除行,您希望第 40 行保留在视口(viewport)的顶部。因此,当行被删除时,滚动条将移动到滚动 Pane 的顶部。当第 40 行最终被删除时,滚动条将位于滚动 Pane 的顶部。

如果是这样,下面的(粗略的)代码可以给你一个想法:

public void removeUpdate(DocumentEvent e) {
//maybeScrollToBottom();
int lineHeight = jTextArea.getPreferredSize().height / jTextArea.getLineCount();
JViewport viewport = jScrollPane.getViewport();
Point position = viewport.getViewPosition();
position.y -= lineHeight;

if (position.y > 0 )
viewport.setViewPosition(position);
}

我怀疑这段代码是否完全按照您想要的方式工作,因为一旦缓冲区已满,您就不能只是将滚动条向下拖动到底部以使视口(viewport)在附加行时不断滚动。但它可能会给你一些想法。

关于java - 智能 JScrollPane 跟随输出文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29177012/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com