不移动鼠标光标时Java动画会断断续续

mon*_*ped 16 java animation swing

我有一个非常简单的动画,一个大字体的文本连续(逐个像素)向左移动.首先将文本转换为图像,然后启动计时器任务,重复(每10-20毫秒)将图像的x坐标递减1,然后执行重绘().

该程序在某些系统上显示出奇怪的行为.在我的电脑上使用nVidia卡,它运行顺畅.在我的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 29

完成绘图后尝试调用此方法:

 Toolkit.getDefaultToolkit().sync();
Run Code Online (Sandbox Code Playgroud)

这会刷新Linux等某些系统使用的图形缓冲区.请参阅Javadoc:http://docs.oracle.com/javase/7/docs/api/java/awt/Toolkit.html#sync()

  • 哦,伙计,非常感谢你,我一直试图修复这个bug几个小时!在调用`repaint()`之后,在框架中也使用`getToolkit().sync()`.(Ubuntu 14.04) (3认同)
  • 这样就解决了我的口吃问题(在Chrubuntu 14.04 Acer C720上),但是我将其切换为`frame.getToolkit().sync();`以避免全局变量.谢谢! (2认同)

tra*_*god 2

分析表明您正在使 所使用的共享线程饱和javax.swing.Timer。一种缓解策略是使用更长的周期和/或更大的增量/减量,如此处所示

附录:此外,您在每次调用 时都需要费力地重新渲染整个图像paintComponent()。相反,使用渲染一次TextLayout,参见此处,并且draw()每次仅渲染新可见的部分。

图像