滚动时阻止JScrollPane进行大量重绘



我在滚动窗格的文本区域中有长文本。我注意到,当我旋转鼠标滚轮时,文本会被严重地重新绘制,甚至可能完全重新绘制。

这是演示应用程序:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class TextArea {
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextArea textArea = new JTextArea();
textArea.setColumns(80);
textArea.setRows(20);
textArea.setLineWrap(true);
final JScrollPane scrollPane = new JScrollPane(textArea);
textArea.append("1234567890 ".repeat(20000));  // Java 11
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
}

如果在sun.java2d.SunGraphics2D.drawString(String, float, float)方法中放置日志断点,则可以很容易地检测到重绘制。对我来说,当我将鼠标滚轮旋转一个单位时,它会记录数千次点击(点击次数取决于帧的大小(。如果我在断点处停下来,我会看到要绘制的字符串的y位置有很大的不同,而且这种差异远不止屏幕的高度。

我认为它应该更好地只重绘可见的线条,甚至可能是新出现的线条。

能否以某种方式设置JScrollPane以优化draw调用的数量?还是Swing中的一个未优化的东西?

当我运行此代码并旋转鼠标滚轮时,GUI根本不会闪烁或更改。我看到滚轮在做什么的唯一原因是JScrollPane选项卡向上移动。

我使用Java 14.0.2按照Java 8标准进行编译。我的电脑在Windows 10上运行。

这并不奇怪,因为文本完全相同。

试试这个完整的可运行代码,看看它是否有什么不同。

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class LargeTextArea implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new LargeTextArea());
}
@Override
public void run() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JTextArea textArea = new JTextArea();
textArea.setColumns(80);
textArea.setRows(20);
textArea.setLineWrap(true);
textArea.append("1234567890 ".repeat(20000)); // Java 11

final JScrollPane scrollPane = new JScrollPane(textArea);
frame.add(scrollPane);

frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}

JTextArea确实为一条长线生成了太多的draw调用,看起来它完全重新绘制了它,而且由于软包装,它被拆分了。

然而,更深入地说,可以看到,在滚动时,剪切区域设置得非常有限(到新的可见空间(,因此Graphics2D能够跳过剪切之外的所有字符串的绘制。

所以不必担心,因为实际上不需要进行太多绘图。

最新更新