Java 保持区域滚动位置
我有一个JScrollPane,其视图端口设置为JTextArea 我大约每秒更新一次JTextArea上显示的(多行)文本。每次文本更新时,JScrollPane都会一直到文本的底部 相反,我想算出当前显示为原始文本中第一行的行号,并将该行作为文本更新后显示的第一行(或者如果新文本没有那么多行,则一直滚动到底) 我的第一次尝试是获取当前插入符号位置,根据该位置绘制线条,然后设置文本区域以显示该线条:Java 保持区域滚动位置,java,user-interface,swing,Java,User Interface,Swing,我有一个JScrollPane,其视图端口设置为JTextArea 我大约每秒更新一次JTextArea上显示的(多行)文本。每次文本更新时,JScrollPane都会一直到文本的底部 相反,我想算出当前显示为原始文本中第一行的行号,并将该行作为文本更新后显示的第一行(或者如果新文本没有那么多行,则一直滚动到底) 我的第一次尝试是获取当前插入符号位置,根据该位置绘制线条,然后设置文本区域以显示该线条: int currentPos = textArea.getCaretPosition(
int currentPos = textArea.getCaretPosition();
int currentLine = 0;
try {
for(int i = 0; i < textArea.getLineCount(); i++) {
if((currentPos >= textArea.getLineStartOffset(i)) && (currentPos < gameStateTextArea.getLineEndOffset(i))) {
currentLine = i;
break;
}
}
} catch(Exception e) { }
textArea.setText(text);
int newLine = Math.min(currentLine, textArea.getLineCount());
int newOffset = 0;
try {
newOffset = textArea.getLineStartOffset(newLine);
} catch(Exception e) { }
textArea.setCaretPosition(newOffset);
int currentPos=textArea.getCaretPosition();
int currentLine=0;
试一试{
对于(int i=0;i=textArea.getLineStartOffset(i))&(currentPos
这几乎可以满足我的需要,但需要用户在文本区域内单击以更改插入符号的位置,这样滚动将保持状态(这不好)
我该如何使用(垂直)滚动位置来实现这一点呢?这是从API文档中拼凑而成的,未经测试:
- 在
上使用JScrollPane
获取视口getViewport()
- 使用
获取左上角的坐标。这些是绝对值,而不是滚动文本的百分比Viewport.getViewPosition()
- 使用
在左上角位置发生变化时收到通知(除其他外)。当然,您可能需要创建一种机制来区分用户更改和程序所做的更改Viewport.addChangeListener()
- 使用
将左上角位置设置为干扰前的位置Viewport.setViewPosition()
- 要停止JTextArea的滚动,您可能需要覆盖其
方法以返回getScrollableTracksViewport{Height | Width}()
false
- 显然,
必须使用setViewPosition
延迟,因为如果太早进行,文本更新将在它之后进行,并使其效果无效invokeLater
- 另外,出于某种奇怪的原因(可能与并发性有关),我必须在构造函数中将正确的值传递给我的
类。我一直在使用Runnable
的“全局”实例,并一直将我的位置设置为0,0orig
我遇到了同样的问题,并发现其中包含了一个很好的解决方案,在这种情况下有效:
DefaultCaret caret = (DefaultCaret) jTextArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
我试过:Point orig=scrollPane.getViewport().getViewPosition();textArea.setText(text);scrollPane.getViewport().setViewPosition(orig);这似乎对我没有任何帮助。有了这些代码,文本区域每次都会一直滚动到底。(并在swing事件调度线程中运行它)。[叹气]我可以看出我应该对此进行测试。我现在就去做,然后再打给你。谢谢。我在这方面做了一些尝试,但似乎并不需要重写。我认为getViewPosition()返回的点对象是共享的,而不是副本,因此我们需要克隆它,以获得相同的效果:最终点orig=(点)scrollPane.getViewport().getViewPosition().clone();textArea.setText(text);SwingUtilities.invokeLater(){new Runnable(){scrollPane.getViewport().setViewPosition(orig);}}}})。。尽管如此,该解决方案99%的时间都有效,但偶尔在进行快速更新时,它会一直向下滚动。works 99%的时间注释既适用于使用克隆的代码,也适用于您答案中的代码。无论如何,对于我的实际目的来说,它已经足够好了,所以我稍后会接受答案。不管怎样,我仍然对如何让它100%的工作充满好奇。我也有类似的问题。由于某些原因,只有在从分派线程调用
setText
时,文本区域才会滚动到底部。请注意,setText
是线程安全的。当不使用调度线程时,一切正常。我真的很想理解为什么。我刚刚意识到:JTextArea处理自己的滚动!这可能会破坏我们控制嵌入JScrollPane的努力。好的,我让它工作了。请参阅我的更新2。此解决方案比公认的解决方案简单得多。这是一个更好的答案,它很简单,工作正常
DefaultCaret caret = (DefaultCaret) jTextArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);