【问题标题】:How to avoid Swing combining repaint() requests?如何避免 Swing 结合 repaint() 请求?
【发布时间】:2015-11-11 22:49:57
【问题描述】:

Swing 通常会组合多个 repaint() 请求,以便只驱动一次 paintComponent() 方法,从而提高性能。通常,这就是您想要的。

但是,在我的应用程序中,这是不可取的。我的组件是一个充满文本的大屏幕(如文本编辑器)。每个字符都包含前景色/背景色和样式(如粗体)等属性。重新绘制整个屏幕(repaint(() 默认执行)是一项昂贵的操作,并且在仅更新屏幕上的几个不同字符时会引入不必要的延迟。

因此,我多次调用 repaint(x, y, width, height) ,但只针对那些实际发生变化的区域(通常为 50 个字符或更少,可能会分散在屏幕上两三个单独的区域,连续区域)。

问题是,通常我会在屏幕的顶部和底部更改字符。我为每个受影响的区域调用重绘,但是 Swing 通过计算要重绘的区域的联合,将我的多个 repaint(...) 请求组合成一个 repaint(...) 请求(这是默认行为)。这将导致对paintComponent() 的单个调用,但带有一个包含所有要更新的区域的大剪切矩形(由getClipBounds() 返回)。因此,无论如何(基于 ClipBounds),我最终都会重新绘制屏幕的大部分区域,这会适得其反,我希望避免这种情况,因为实际上只有一小部分屏幕被修改过,因此需要重新粉刷。

问题:有什么办法可以缓解这种行为,让我的 paintComponent() 方法只重绘那些已修改的区域,并避免对未修改区域进行不必要的重绘?

根据要求提供更多详细信息:

该类是从 JComponent 派生的。基本上,它只是一个“空”窗口,我使用 Swing 的 API 在其上绘制文本字符。窗口的最大尺寸约为 83 行 x 每行 320 列(这是在 Apple Cinema 显示器上),因此对于 8x16 字体,即为 2560x1328。

基本上,该应用程序是一个文本编辑器(想想:vi)。显示屏的底线是状态行。在最坏的情况下,我可能会将光标移动到窗口顶部右侧的一个位置。这将导致窗口底部的状态行被更新以反映新的光标位置(行、列)。因此,我们在窗口顶部有一些位置发生变化,在窗口底部有一些位置发生变化。我会发出 2 个 repaint(...) 请求,一个用于窗口的每个修改区域。但是,repaint() 将结合这两个请求,并使用边界矩形(定义要重新绘制的区域)调用一次 paintComponent(),该边界矩形是实际更新的两个区域的 union。生成的矩形将非常大,从窗口顶部延伸到底部。因此,在paintComponent() 中,我最终重新绘制了屏幕的很大一部分,即使大部分都没有被修改。这就是我要避免的。

【问题讨论】:

  • 您是否考虑过使用文本组件(如JTextPaneJEditorPane)来代替?
  • 您能提供更多信息吗?正在重新绘制什么样的组件?

标签: java swing paintcomponent repaint


【解决方案1】:

有什么办法可以缓解这种行为,让我的paintComponent()方法只重绘那些已经修改过的区域,

您可以尝试使用JComponent 类的paintImmediately(...) 方法。

这将导致立即完成多个较小的绘制请求,而没有 RepaintManager 的好处。只有您可以决定多个较小的请求比单个较大的绘制请求执行得更好。

【讨论】:

  • AFAIK 必须从 EDT 中调用
  • 是的,paintImmediately(...) 似乎解决了我的问题,因为它基本上在 paintImmediately(...) 调用的范围内驱动 paintComponent(...)。不是 Swing 爱好者,我忽略了这一点,而你是我第一次看到它。正如 mKorbel 所指出的,这一切都必须在 EDT 下进行,这是我的代码符合的先决条件。我应该指出 repaint(...) 通常是更新 GUI 的“正确”方式,但在我的情况下,由于上述原因,repaint(...) 效果不佳,而 paintImmediately(.. .) 达到预期目标。谢谢!
猜你喜欢
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 2020-09-23
相关资源
最近更新 更多