1

我正在将动画绘制到摇摆 JPanel 上。1024x1024 屏幕被分成 2000 块,它们完全覆盖屏幕(没有重叠)。

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

缓冲的图像没有加速并且不是易失性的。我将它的优先级设置为1。

框架根窗格已优化。前缓冲器和后缓冲器都被加速但不挥发。

这工作正常。

分析表明几乎所有的图形时间都花在绘制缓冲图像上,正如人们所期望的那样,使用一些脏矩形似乎并不能帮助减少绘制时间。

如果我用它的确切形状剪辑缓冲图像的绘图,则该部分被绘制并且屏幕的其余部分变为白色。

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

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

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

我看到的建议包括 Toolkit.getDefaultToolkit().setDynamicLayout(true); System.setProperty("sun.awt.noerasebackground","true");

其他建议包括立即绘制,以及子类化 JComponent 而不是 JPanel。

我觉得这一切都有些令人困惑。

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

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

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

4

2 回答 2

3

这里有一些建议:

  • repaint()对每一毫秒的需求进行批判性检查;特别是,看看是否可以合并一些更新。

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

  • 不需要缩放时调用drawImage()速度最快,如下所示AnimationTest

  • 总是尽可能地预先计算图像,正如本文所建议的那样,KineticModel它说明了几种动画技术。

  • TexturePaint, 用于KineticModel, 也在这里显示。

  • IndexColorModel,在这里说明, 可能适用。

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

于 2012-08-06T19:58:43.157 回答
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);
            }
        } 

    }
}
于 2012-08-06T20:21:26.343 回答