1

スイングJPanelにアニメーションを描いています。1024x1024 の画面は 2000 個の部分に分割され、画面を正確にカバーします (オーバーラップはありません)。

各部分は画面の非常に小さな部分です (2000 分の 1)。アニメーションは、バッファリングされた画像のピクセルを変更し、reaint() を呼び出すことで、ミリ秒ごとに 1 つのピースを描画します。そのため、画面全体が 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");

その他の提案としては、すぐにペイントする、JPanel の代わりに JComponent をサブクラス化するなどがあります。

これはすべてややこしいと思います。

この OS にできるだけ依存しないようにしたいのですが、アプリは主に 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)(コンポーネント全体が汚れていない限り)関数が使用されるため、画像のごく一部を更新するだけで済みます。うまくいけば、サンプルコードはOSに依存していません-それがあなたのために機能しない場合は私に知らせてください。

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 に答える