20

私は非常に単純なアニメーションを持っています。大きなフォントのテキストが連続的に (ピクセルごとに) 左に移動します。テキストは最初に画像に変換され、次にタイマー タスクが開始され、繰り返し (10 ~ 20 ミリ秒ごとに) 画像の x 座標が 1 減分され、repaint() が実行されます。

このプログラムは、一部のシステムで奇妙な動作を示します。nVidia カードを搭載した私の PC では、スムーズに動作します。私の Vaio ノートブック、BeagleBoneBlack、および友人の Mac では、ひどく途切れます。しばらく静止しているように見えますが、左に約 10 ピクセルジャンプし、再び一時停止というように続きます。

私が困っているのは、これらのシステムでは、マウスに触れていない場合にのみアニメーションが途切れるという事実です。ウィンドウ内でマウス カーソルをゆっくり動かしたり、ウィンドウ自体をドラッグしたりする限り、アニメーションは完全にスムーズに実行されます。

誰でもこれを説明できますか?プログラムは次のとおりです。

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.*;

class Textimg extends JComponent
{
    String      str;
    Font        font;
    int         x = 0;
    final int   ytext = 136;
    Image       img;

    public Textimg(String s)
    {
        str = s;
        font = new Font("Noserif", Font.PLAIN, 96);
        setLayout(null);
    }

    protected void paintComponent(Graphics g)
    {
        if (img == null)
        {
            img = createImage(4800, 272);
            Graphics gr = img.getGraphics();

            gr.setFont(font);
            gr.setColor(Color.BLACK);
            gr.fillRect(0, 0, 4800, 272);
            gr.setColor(new Color(135, 175, 0));
            gr.drawString(str, 0, ytext);
            gr.dispose();
        }

        g.drawImage(img, x, 0, this);
    }

    public void addX(int dif)
    {
        if (isVisible())
        {
            x = x + dif;

            Graphics g = getGraphics();

            if (g != null) paintComponent(g);
        }
    }
} 


public class Banner extends JFrame 
{ 
    StringBuffer    buf;
    int             sleeptime = 10;

    Banner(String path) throws IOException 
    { 
        setSize(new Dimension(480, 272));
        setTitle("Java Test");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(null);

        BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(path), "UTF-8"));

        buf = new StringBuffer();

        while (true) 
        {
           String line = reader.readLine();

           if (line == null) break;
           buf.append(line);
        }

        final Textimg textimg = new Textimg(buf.toString());

        add(textimg);
        textimg.setBounds(0, 0, 480, 272);

        final javax.swing.Timer timer = new javax.swing.Timer(200, new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                textimg.addX(-1);
            }
        });

        timer.setDelay(sleeptime);
        timer.start();
    }

    //----------------------------------------------------------------------

    public static void main(String[] args) throws Exception
    {
        new Banner(args[0]).setVisible(true);
    }
}
4

4 に答える 4

41

描画が完了したら、このメソッドを呼び出してみてください。

 Toolkit.getDefaultToolkit().sync();

これにより、Linux などの一部のシステムが使用するグラフィック バッファがフラッシュされます。Javadoc を参照してください: http://docs.oracle.com/javase/7/docs/api/java/awt/Toolkit.html#sync()

于 2014-10-15T17:09:05.213 に答える
3
  • これは Swing でのカスタム ペインティングの方法ではありませgetGraphicsん。paintComponent代わりに、状態を更新して を呼び出しますrepaint
  • マジックナンバーに頼らず、手元にある情報を使って(getWidthgetHeight
  • Swing コンポーネントは二重にバッファリングされるため、独自のバッファリング戦略を作成する必要はほとんどありません。この単純な行為があなたの絵を遅くしている可能性があります
  • に電話する必要がありますsuper.paintComponentJComponent不透明ではなく、そうしないと厄介なペイント アーティファクトが発生する可能性があるため、 これは ではさらに重要です。
  • JComponent#getPreferredSize効率的にレイアウト マネージャーと連携できるようにオーバーライドする必要があります。
  • たとえば、40 ミリ秒 (約 25 fps) など、遅延が短いほど、より良い錯覚が生じることがあります。

オブジェクトの管理と最適化により、500 個のアニメーション オブジェクトを 4500 個まで増やすことができたSwing アニメーションの実行速度が非常に遅いことを確認してください。

また、特にAWT と Swingでのカスタム ペインティングとペインティングの実行もご覧ください。

于 2013-10-20T19:37:58.790 に答える
2

プロファイリングは、によって使用される共有スレッドを飽和させていることを示していますjavax.swing.Timer緩和戦略の 1 つは、ここに示すように、より長い期間および/またはより大きな増分/減分を使用することです。

補遺: さらに、 を呼び出すたびに画像全体を再レンダリングするのに手間がかかりますpaintComponent()。代わりに、ここに表示されているを使用して1 回レンダリングし、毎回新しく表示される部分のみをレンダリングします。TextLayoutdraw()

画像

于 2013-10-20T17:06:28.767 に答える
0

問題が解決しました!

私自身の質問に答えるために:連続入力(マウスまたはキーボード)がアニメーションをスムーズに実行することに気付いた後クラスのオブジェクトを使用して、プログラム自体で入力を生成できることを思い出しましたjava.awt.Robot。これは簡単な回避策につながります。ロボットを作成し、アニメーション サイクルごとにキーを押すかマウスを動かします。

final Robot robot = new Robot();
javax.swing.Timer timer = new javax.swing.Timer(initialDelay, new ActionListener()
{
    public void actionPerformed(ActionEvent e)
    {
        // update your image...

        robot.keyPress(62);
     }
});

これは大雑把ですが、完全に機能します。

于 2013-10-22T10:31:44.243 に答える