gpt4 book ai didi

Java JTextPane + JScrollPane : de/activate automatic scrolling

转载 作者:行者123 更新时间:2023-11-30 07:29:02 25 4
gpt4 key购买 nike

我目前正在用 Java 编写一个简单的聊天,目前我遇到了这个问题:我希望我的输出 JTextPane 表现得像你期望的那样从一个好的聊天中,即默认情况下,文本在新文本到达时自动滚动(使用 outputfield.setCaretPosition(outputdocument.getLength())),但是当用户向上滚动时应该被禁用,当然当用户再次滚动到底部时重新启用。

我试着摆弄 ScrollBars 和所有的东西,但我似乎无法找到一种方法来检测 ScrollBar 是否在底部。

我通过创建一个 JTextPane 和一个 JScrollPane 并将一个放入另一个来创建可滚动的输出区域。

JTextPane outputpane = new JTextPane
...
JScrollPane outputscroll = new JScrollPane(outputpane);
outputscroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

编辑:这是我用来创建组件和显示新消息的代码:

// lots of imports


public class RoomFrame extends JFrame implements ListSelectionListener, ActionListener, Comparable, Runnable
{
public static final String DEFAULT_FONT = "Courier";
public static final int DEFAULT_FONT_SIZE = 12;

private JTextPane mOutputField;
private JScrollPane mOutputScroll;

private StyledDocument mOutputDocument;


public RoomFrame(...)
{
super(...);

createGUI();
setOutputStyles();
setVisible(true);

new Thread(this).start();
}

// ========================================================

private void createGUI()
{
Color borderhighlightouter = new Color(220, 220, 220);
Color borderhighlightinner = new Color(170, 170, 170);
Color bordershadowouter = new Color(120, 120, 120);
Color bordershadowinner = new Color(170, 170, 170);

setLayout(new GridBagLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(500, 400);


// -----------------------------
// Output
mOutputField = new JTextPane();
mOutputField.setEditable(false);
mOutputField.setBackground(new Color(245, 245, 245));
mOutputDocument = mOutputField.getStyledDocument();

mOutputScroll = new JScrollPane(mOutputField);

mOutputScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
mOutputScroll.setPreferredSize(new Dimension(250, 250));
mOutputScroll.setMinimumSize(new Dimension(50, 50));
mOutputScroll.setOpaque(false);
mOutputScroll.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0), BorderFactory.createBevelBorder(BevelBorder.LOWERED, borderhighlightouter, borderhighlightinner, bordershadowouter, bordershadowinner)));

getContentPane().add(mOutputScroll);
}

private void setOutputStyles()
{
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);

Style regular = mOutputDocument.addStyle("regular", def);
StyleConstants.setFontFamily(def, DEFAULT_FONT);
StyleConstants.setFontSize(def, DEFAULT_FONT_SIZE);
StyleConstants.setFirstLineIndent(def, 100.0f);

Style nickname = mOutputDocument.addStyle("username", def);
StyleConstants.setBold(nickname, true);
StyleConstants.setForeground(nickname, new Color(50, 50, 220));

Style highlight = mOutputDocument.addStyle("highlight", def);
StyleConstants.setBold(highlight, true);
StyleConstants.setBackground(highlight, new Color(150, 0, 0));

Style join = mOutputDocument.addStyle("join", def);
StyleConstants.setBold(join, true);
StyleConstants.setForeground(join, new Color(20, 100, 20));

Style leave = mOutputDocument.addStyle("leave", def);
StyleConstants.setBold(leave, true);
StyleConstants.setForeground(leave, new Color(100, 100, 20));

Style topic = mOutputDocument.addStyle("topic", def);
StyleConstants.setBold(topic, true);
StyleConstants.setUnderline(topic, true);

Style error = mOutputDocument.addStyle("error", def);
StyleConstants.setBold(error, true);
StyleConstants.setForeground(error, new Color(255, 0, 0));

Style kick = mOutputDocument.addStyle("kick", def);
StyleConstants.setBold(kick, true);
StyleConstants.setForeground(kick, new Color(150, 0, 0));
}

private final boolean shouldScroll()
{
int min = mOutputScroll.getVerticalScrollBar().getValue() + mOutputScroll.getVerticalScrollBar().getVisibleAmount();
int max = mOutputScroll.getVerticalScrollBar().getMaximum();

return min == max;
}

// ========================================================

public void displayMessage(String message)
{
displayMessage(message, "");
}

public void displayMessage(String message, String style)
{
displayMessage(message, style, true);
}

public void displayMessage(String message, String style, boolean addnewline)
{
String newline = (addnewline ? "\n" : "");

style = (style.equals("") ? "regular" : style);
message = message.replace("\n", " ");

// check for highlight

try
{
mOutputDocument.insertString(mOutputDocument.getLength(),
String.format("%s%s", message, newline),
mOutputDocument.getStyle(style));
}
catch (Exception e) {}

// if (shouldScroll())
// mOutputField.setCaretPosition(mOutputDocument.getLength());
}

public void run()
{
while (true)
{
if (shouldScroll())
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
mOutputScroll.getVerticalScrollBar().setValue(mOutputScroll.getVerticalScrollBar().getMaximum());
}
});
}

try { Thread.sleep(500); }
catch (InterruptedException e) { break; }
}
}

public void valueChanged(ListSelectionEvent event)
{

}

public void actionPerformed(ActionEvent event)
{

}

public final int compareTo(Object o) { return this.toString().compareTo(o.toString()); }
}


编辑: 感谢 fireshadow52 到 another similar question 的链接我终于让它按照我想要的方式工作:

private boolean isViewAtBottom()
{
JScrollBar sb = mOutputScroll.getVerticalScrollBar();
int min = sb.getValue() + sb.getVisibleAmount();
int max = sb.getMaximum();
System.out.println(min + " " + max);
return min == max;
}

private void scrollToBottom()
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
mOutputScroll.getVerticalScrollBar().setValue(mOutputScroll.getVerticalScrollBar().getMaximum());
}
});
}

public void displayMessage(String message, String style, boolean prependnewline)
{
String newline = (prependnewline ? "\n" : "");
boolean scroll = isViewAtBottom() && prependnewline;

style = (style.equals("") ? "regular" : style);
message = message.replace("\n", " ");

try
{
mOutputDocument.insertString(mOutputDocument.getLength(),
String.format("%s%s", newline, message),
mOutputDocument.getStyle(style));
}
catch (Exception e) {}

if (scroll)
scrollToBottom();
}

再次感谢您的帮助!

最佳答案

如果您只想在位于底部时滚动,那么这应该有帮助。

使用此方法检查滚动条是否在末端(或底部),如果是,使用 setCaretPosition(Component.getDocument().getLength()); 自动向下滚动:

public boolean shouldScroll() {
int minimumValue = scrollPane.getVerticalScrollBar().getValue() + scrollPane.getVerticalScrollBar().getVisibleAmount();
int maximumValue = scrollPane.getVerticalScrollBar().getMaximum();
return maximumValue == minimumValue;
}

我在使用 Google 时发现了类似的结果,这使我找到了一种与此方法类似的方法,该方法按要求工作。

编辑:确保它在 invokeLater() 中完成,因为它需要在滚动完成之前更新。

我使用的完整示例:

public class ScrollTest extends Thread {

private JFrame frame;

private JTextArea textArea;

private JScrollPane scrollPane;

public static void main(String[] arguments) {
new ScrollTest().run();
}

public ScrollTest() {
textArea = new JTextArea(20, 20);
scrollPane = new JScrollPane(textArea);

frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}

public void run() {
while (true) {
textArea.append("" + Math.random() + "\n");
if (shouldScroll()) {
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum());
}

});
}
try {
Thread.sleep(500);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}

public boolean shouldScroll() {
int minimumValue = scrollPane.getVerticalScrollBar().getValue() + scrollPane.getVerticalScrollBar().getVisibleAmount();
int maximumValue = scrollPane.getVerticalScrollBar().getMaximum();
return maximumValue == minimumValue;
}

关于Java JTextPane + JScrollPane : de/activate automatic scrolling,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8789371/

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