我不太清楚怎么说这个,所以请耐心等待。
我在容器JPanel
中有两个JPanel
,OverlayLayout
。容器中的JPanel
都覆盖paint(Graphics)
。
底部JPanel
是不透明的,会绘制一些相当复杂的图形,因此渲染需要“很长”的时间(10秒或100毫秒)。
顶部JPanel
是透明的,只是根据鼠标输入绘制一个矩形或直线或简单的形状,所以它非常快。
有没有办法设置,所以当我更改上面板中的简单形状时,它不会重绘底部面板?(例如它以某种方式缓存底部面板)
我很熟悉w /概念,如bitblt,double-buffering和XOR-drawing,但不确定在这里应用什么。
答案 0 :(得分:4)
您最好使用单个JComponent
并创建BufferedImage
来存储底部图片。当paintComponent
上的JComponent
操作发生时,您只需将底部图像blit并使用Graphics
对象在其上进行任何进一步绘制(从存储状态)。应该相当有效。
你想要在另一个帖子中对底部BufferedImage
进行复杂的绘图操作,正如另一张海报所提到的那样(偶然省略了这个,对不起:))。但是,您不希望对此图像造成争用,因此您必须为此存储一个额外的BufferedImage
,并在绘制操作完成时立即将其同步到另一个图像。
答案 1 :(得分:3)
关注复杂的面板,关键是将paintComponent()
除drawImage()
以外的所有内容分解。将其他所有内容放在另一个不断更新屏幕外缓冲区的线程中。定期更新屏幕,以保持简单面板的响应速度。唯一困难的部分是同步,但SwingWorker
是一个不错的选择。还有更多here。
答案 2 :(得分:3)
可以肯定的是,如果上面板是完整repaint()
的目标,那么较低的面板也是。{/ p>
也许您可以尝试优化区域以在上面板上重新绘制,以避免重新绘制所有较低的区域。但如果上面板中的彩绘矩形覆盖整个区域,那么您最终会再次使用完整的repaint()
。
通常情况下,Swing会尝试优化需要重绘的区域,但是当在短时间内执行多次重绘时它也聚合这些区域,如果我记得很清楚,聚合区域只是一个矩形,它是所有重绘矩形,并不总是优化,但允许快速计算重绘事件的创建。
现在,我认为您应该遵循先前回复中给出的建议;实际上,你应该真的避免使用paint()
方法来执行那么长的计算(ms的几十分之一应该是真正的最大值)。如果您不希望GUI看起来对最终用户没有响应,那么绘画应该尽可能快。因此,有利于仅执行一次计算(如果可能,在EDT之外),将结果存储在BufferedImage
中,您只需稍后在paint()
方法中绘制。
编辑:添加了其他反射来源
如果要优化点列表的更新但仍保留在paint()
方法中,则可以使用传递的Graphics
的剪切区域来限制对绘图方法的调用,像:
Rectangle clip = g.getClipBounds();
for (Point p: allPoints) {
if (clip.contains(p)) {
// draw p with g graphics
}
}
您甚至可以尝试使用QuadTree而不是简单的List
来优化要绘制的点列表,但您必须自己编写代码(或者找一些免费的实现,那里可能是他们中的一小部分)。使用四叉树,您可以优化时间以查找必须重绘的所有点的列表(基于Graphics
剪切矩形)并仅重绘这些点。
答案 3 :(得分:2)
通过trashgod和jfpoilpret回答补遗
1 / OverlayLayout是如何布局JPanels的奇怪方法,你是一次JPanel(没有OverlayLayout和Translucentcy)同样的输出
2 /(10s或100s毫秒)可能是小值,因为存在Native OS Latency(今天的操作系统和PC为45-75ms)3 /同步将通过在BackGround任务上使用SwingWorker以及绘制流程到JPanel的顺序,方向和同步来管理,也许你的油漆太快/太快
4 /你没有详细描述关于paint()/ paintComponent()
的方法,地点和内容 if (SwingUtilities.isEventDispatchThread()) {
paintImmediately(int x, int y, int w, int h) // or Rectangle r
} else {
Runnable doRun = new Runnable() {
@Override
public void run() {
repaint(long tm, int x, int y, int width, int height) // or Rectangle r
}
};
SwingUtilities.invokeLater(doRun);
}