如何加快这个摆动动画?

时间:2012-08-06 17:19:58

标签: java swing animation bufferedimage

我在一个摇摆的JPanel上画动画。 1024x1024屏幕分为2000个部分,完全覆盖屏幕(不重叠)。

每一块都是屏幕的一小部分(1/2000')。动画通过更改缓冲图像中的像素并调用reaint(),每毫秒绘制一个片段。所以在整个屏幕上每2秒更换一次。动画在java.util.Timer任务中运行。

缓冲图像未加速且不易变。我将它的优先级设置为1。

优化框架根窗格。正面和背面缓冲都是加速但不易变的。

这没问题。

分析表明,几乎所有的grahics时间都是按照人们的预期绘制缓冲图像,使用一些脏矩形似乎无助于缩短绘制时间。

如果我使用精确的形状剪切缓冲图像的图形,那么该图块会被绘制,而屏幕的其余部分会变为白色。

我想要的是让屏幕的其余部分保持原样,只是让剪裁的形状被绘制。

制作每个像素的像素需要混合10个图层,因此在那里进行了一些计算。 可以/应该在awt计时器线程中做得更好吗?

或者我应该使用画布和更新技巧http://java.sun.com/products/jfc/tsc/articles/painting/src/UpdateDemo.java

我见过包含Toolkit.getDefaultToolkit()的建议.setDynamicLayout(true); System.setProperty( “sun.awt.noerasebackground”, “真”);

其他建议包括paintimmedialtely,并继承JComponent而不是JPanel。

我发现这有点令人困惑。

我希望尽可能保持这个操作系统独立,但该应用程序将主要在Windows 7上运行。

我在这里采取的下一个(小)逻辑步骤是什么?

更新:使用画布(没有更新技巧)显着减少了绘制缓冲图像所花费的时间。而不是这个在探查器的顶线,我找不到它!当我使用面板时,我可能会比我应该做的更多。

2 个答案:

答案 0 :(得分:3)

以下是一些建议:

  • 严格审查每毫秒repaint()的需要;特别是,看看是否可以合并某些更新。

  • 考虑java.swing.Timer的便利性,它在EDT上呈现并支持合并事件。

  • 如果不需要缩放,则drawImage()的呼叫速度最快,如AnimationTest所示。

  • 始终按照本KineticModel中的建议尽可能预先计算图像,以说明几种动画技术。

  • TexturePaint中使用的
  • KineticModel也会显示here

  • IndexColorModel,图示为here,可能适用。

  • sscce将允许您隔离各种方法以便于分析。

答案 1 :(得分:2)

编辑更好的例子

基本上我们可以使用RepaintManager来跟踪/更新我们每毫秒更改的几个像素。肮脏的区域将累积,直到油漆实际上能够发生。当油漆发生时,它使用paintImmediately(int x, int y, int w, int h)函数(除非整个组件都是脏的) - 所以我们只是更新图像的一小部分。希望示例代码不依赖于操作系统 - 如果它不适合您,请告诉我。

import java.awt.*;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class UpdatePane extends JPanel{
    final int MAX = 1024;

    //The repaint manager in charge of determining dirty pixels
    RepaintManager paintManager = RepaintManager.currentManager(this);

    //Master image
    BufferedImage img = new BufferedImage(MAX, MAX, BufferedImage.TYPE_INT_RGB);


    @Override
    public void paintComponent(Graphics g){
        g.drawImage(img, 0, 0, null);
    }

    public void paintImmediately(int x, int y, int w, int h){
        BufferedImage img2 = img.getSubimage(x, y, w, h);
        getGraphics().drawImage(img2, x, y, null);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                final UpdatePane outside = new UpdatePane(); 

                outside.setPreferredSize(new Dimension(1024,1024));

                JFrame frame = new JFrame();
                frame.add(outside);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setVisible(true);

                outside.new Worker().execute();
            }
        });
        }

    //Goes through updating pixels (like your application would)
    public class Worker extends SwingWorker<Integer, Integer>{
        int currentColor = Color.black.getRGB();
        public int x = 0;
        public int y = 0;
        @Override
        protected Integer doInBackground() throws Exception {
            while(true){
                if(x < MAX-1){
                    x++;
                } else if(x >= MAX-1 && y < MAX-1){
                    y++;
                    x = 0;
                } else{
                    y = 0;
                    x = 0;
                }

                if(currentColor < 256){
                    currentColor++;
                } else{
                    currentColor = 0;
                }

                img.setRGB(x, y, currentColor); 

                //Tells which portion needs to be repainted [will call paintImmediately(int x, int y, int w, int h)]
                paintManager.addDirtyRegion(UpdatePane.this, x, y, 1, 1);
                Thread.sleep(1);
            }
        } 

    }
}