Sam*_*ami 7 java user-interface swing
我有一个JSCrollPane,其中JTextArea设置为其视图端口.
我连续更新JTextArea上显示的(多行)文本大约每秒一次.每次文本更新时,JScrollPane都会一直到文本的底部.
相反,我想弄清楚当前显示为原始文本中第一行的行号,并将该行作为文本更新后显示的第一行(或者如果新文本没有那么多行,然后一直滚动到底部).
我这样做的第一次尝试是获取当前插入位置,根据该位置计算线条,然后设置文本区域以显示该行:
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);
Run Code Online (Sandbox Code Playgroud)
这几乎可以满足我的需求,但要求用户在文本区域内单击以更改插入位置,以便滚动将保持状态(这不是很好).
我如何使用(垂直)滚动位置来代替?
bdu*_*riu 13
我遇到了同样的问题,发现这个答案包含一个很好的解决方案,适用于这种情况:
DefaultCaret caret = (DefaultCaret) jTextArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
Run Code Online (Sandbox Code Playgroud)
这是从API文档拼凑而未经测试的:
getViewport()您JScrollPane获取视野的保持.Viewport.getViewPosition()获取左上角坐标.这些是绝对的,而不是滚动文本的百分比.Viewport.addChangeListener()在左上角位置发生变化时通知(除其他外).当然,您可能希望创建一种机制来区分用户更改和程序所做的更改.Viewport.setViewPosition()将左上角位置设置为干扰之前的位置.更新:
getScrollableTracksViewport{Height|Width}()返回的方法false.更新2:
以下代码可以满足您的需求.令人惊讶的是,我必须付出多少努力才能让它发挥作用:
setViewPosition必须推迟使用,invokeLater因为如果它太早完成,文本更新将在它之后,并使其效果无效.Runnable在构造函数中将正确的值传递给我的类.我一直在使用"全局"实例orig并且一直将我的位置设置为0,0.public class Sami extends JFrame implements ActionListener {
public static void main(String[] args) {
(new Sami()).setVisible(true);
}
private JTextArea textArea;
private JScrollPane scrollPane;
private JButton moreTextButton = new JButton("More text!");
private StringBuffer text = new StringBuffer("0 Silly random text.\n");
private Point orig = new Point(0, 0);
public Sami() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
this.textArea = new JTextArea() {
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
};
this.scrollPane = new JScrollPane(this.textArea);
getContentPane().add(this.scrollPane, BorderLayout.CENTER);
this.moreTextButton.addActionListener(this);
getContentPane().add(this.moreTextButton, BorderLayout.SOUTH);
setSize(400, 300);
}
@Override
public void actionPerformed(ActionEvent arg0) {
int lineCount = this.text.toString().split("[\\r\\n]").length;
this.text.append(lineCount + "The quick brown fox jumped over the lazy dog.\n");
Point orig = this.scrollPane.getViewport().getViewPosition();
// System.out.println("Orig: " + orig);
this.textArea.setText(text.toString());
SwingUtilities.invokeLater(new LaterUpdater(orig));
}
class LaterUpdater implements Runnable {
private Point o;
public LaterUpdater(Point o) {
this.o = o;
}
public void run() {
// System.out.println("Set to: " + o);
Sami.this.scrollPane.getViewport().setViewPosition(o);
}
}
}
Run Code Online (Sandbox Code Playgroud)