java + Swing:矩形或其他“精灵”的高效叠加

时间:2011-05-26 19:51:20

标签: java swing graphics

我不太清楚怎么说这个,所以请耐心等待。

我在容器JPanel中有两个JPanelOverlayLayout。容器中的JPanel都覆盖paint(Graphics)

底部JPanel是不透明的,会绘制一些相当复杂的图形,因此渲染需要“很长”的时间(10秒或100毫秒)。

顶部JPanel是透明的,只是根据鼠标输入绘制一个矩形或直线或简单的形状,所以它非常快。

有没有办法设置,所以当我更改上面板中的简单形状时,它不会重绘底部面板?(例如它以某种方式缓存底部面板)

我很熟悉w /概念,如bitblt,double-buffering和XOR-drawing,但不确定在这里应用什么。

4 个答案:

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