我有一个非常简单的动画,一个大字体的文字连续(逐个像素)向左移动。首先将文本转换为图像,然后启动计时器任务,重复(每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);
}
}
答案 0 :(得分:27)
完成绘图后尝试调用此方法:
Toolkit.getDefaultToolkit().sync();
这会刷新Linux等某些系统使用的图形缓冲区。请参阅Javadoc:http://docs.oracle.com/javase/7/docs/api/java/awt/Toolkit.html#sync()
答案 1 :(得分:2)
Profiling表示您正在使javax.swing.Timer
使用的共享线程饱和。一种缓解策略是使用更长的周期和/或更大的增量/减量,如here所示。
附录:此外,您在每次调用paintComponent()
时都会费力地重新渲染整个图像。相反,每次使用TextLayout
,here和draw()
仅使用新显示的部分,将其一次渲染
答案 2 :(得分:2)
getGraphics
,你不应该自己打电话给paintComponent
,这不是自定义绘画是如何在Swing中完成的。而是更新状态并调用repaint
。 getWidth
和getHeight
)super.paintComponent
。这对于JComponent
来说更为重要,因为它不是不透明的,如果不这样做可能会导致一些令人讨厌的油漆伪影。 JComponent#getPreferredSize
,以便它可以有效地与布局管理器配合使用。看看Swing animation running extremely slow,通过一些对象管理和优化,可以将500个动画对象增加到4500个。
答案 3 :(得分: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);
}
});
这是一种kludge,但效果很好。