阻止滚动时JScrollPane的大量重绘

huangapple go评论73阅读模式
英文:

Stop JScrollPane from high amount of redraws when scrolling

问题

以下是翻译好的部分:

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

这是演示的应用程序:

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以优化绘制调用的数量?还是这是 Swing 中未经优化的问题?

英文:

I have long text in Text Area placed to the Scroll Pane. I've noticed that when I rotate the mouse wheel, the text is redrawn severely, maybe even entirely.

This is the demo app:

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);
  }
}

Redrawing can be easily detected if you place a logging breakpoint to the sun.java2d.SunGraphics2D.drawString(String, float, float) method. For me, it logs a couple of thousands hits when I rotate mouse wheel by a single unit (the number of hits depends on the size of frame). If I stop at breakpoint, I see that y position of the string to draw differs a lot and the difference is much more than the height of my screen.

I think it should better redraw only visible lines, or maybe even newly appeared lines.

Can JScrollPane be set up somehow to optimize the amount of draw calls? Or is it an unoptimized thing in Swing?

答案1

得分: 0

当我运行这段代码并旋转鼠标滚轮时,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);
    }
}
英文:

When I run this code and spin the mouse scroll wheel, the GUI doesn't flicker or change at all. The only reason I see my scroll wheel doing something is the JScrollPane tab moves upward.

I compiled to the Java 8 standard, using Java 14.0.2. My computer runs on Windows 10.

Not surprising, since the text is identical.

Try this complete runnable code and see if it makes a difference.

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);
	}
}

答案2

得分: 0

JTextArea 对于长行生成了太多的绘制调用,看起来像是完全重新绘制了它,而且由于软换行,它被分割了。

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

因此,无需担心,实际上不需要执行太多的绘制操作。

英文:

JTextArea indeed generates too much draw calls for a long line, seems like it redraws it fully and because of soft wrapping, it's split.

However, going deeper, it's visible that while scrolling, clipping area is set quite restrictively (to the newly visible space), so Graphics2D is able to skip drawing of all the strings that are outside of clipping.

So there is no need to worry because actually not much drawing should be performed.

huangapple
  • 本文由 发表于 2020年10月23日 04:04:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/64489759.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定