2011-05-26 26 views
2

我不太确定如何说明这一点,请耐心等待。java + Swing:矩形或其他“精灵”的高效叠加

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

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

顶部JPanel是透明的,只是绘制一个矩形或行或基于鼠标输入简单的形状,所以它的真快。

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

我很熟悉w /像bitblt,双缓冲和异或绘图的概念,但不知道在这里应用什么。

回答

4

你最好关闭使用单一JComponent和创建BufferedImage存储底部的图像。当paintComponent操作发生在JComponent上时,您只需拍摄底部图像,然后使用Graphics对象对其进行绘制(从存储状态开始)。应该相当有效。

你会想在另一个线程中对底部BufferedImage进行复杂的绘制操作,因为另一个海报提到(忽略这个意外,对不起:))。但是,您不希望在该图像上引起争用,因此您必须为此另存为BufferedImage,并在完成绘图操作的同时,将其同步到其他图像上。

3

着眼复杂面板上,关键是除了drawImage()融通东西展现出来的paintComponent()。将其他所有内容放在另一个线程中,以不断更新屏幕外缓冲区。以一定的速率定期更新屏幕,以保持简单面板的响应。唯一困难的部分是同步,但SwingWorker是一个不错的选择。还有更多here

3

什么肯定的是,如果上面板的目标是一个完整的repaint(),那么下一个会是也。

也许你可以尝试优化区域重画上面板上,以避免重画所有较低的一个。但是,如果上面板上的彩色矩形覆盖整个区域,那么您将再次以完整的repaint()结束。

通常情况下,Swing会尝试优化需要重绘的区域,但在短时间内执行多次重绘时也会聚合这些区域,如果我没记错,聚合区域只是一个矩形,即联合的所有重绘矩形,这并不总是优化,但允许快速计算重绘事件创建。

现在,我想你应该按照以前的回复中给出的建议;事实上,你应该避免拥有一个可以执行长时间计算的方法(几十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裁剪矩形),并仅重绘这些点。

+0

听起来像是不错的想法。这不是说它有很多计算,而是我绘制了数万个点。 – 2011-05-27 00:44:30

+0

是的,但是绘制1000点的10点会使用大量的CPU。所以将它们绘制在paint()之外的'BufferedImage'上并且仅在点列表(或者它们的坐标)改变时才更新'BufferedImage',在重建'BufferedImage'之后,你只需要调用'重绘()'。 – jfpoilpret 2011-05-27 04:36:48

2

附录由trashgod和jfpoilpret答案

1/OverlayLayout是奇怪的方式如何布局JPanels,你同样的输出与曾经的JPanel(不OverlayLayout和Translucentcy)

2 /(10S或100S毫秒)可能很小,因为有Native OS延迟(今天的操作系统和PC为45-75ms)

3 /同步将通过在后台任务上使用SwingWorker进行管理,并且通过使用后台绘图进程的顺序,指示和同步来管理JPanel,也许你的油漆太快/太快

4 /你没有介绍更多有关如何,在何处以及其中约油漆()/的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); 
    } 
+0

这些都是好的问题。 – trashgod 2011-05-27 15:46:08