我有一个简单的Java / Swing应用程序,试图通过从左到右移动框来设置框的动画:
public class TestFrame extends JFrame {
protected long startTime = new Date().getTime();
public class MainPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
// calculate elapsed time
long currentTime = new Date().getTime();
long timeDiff = currentTime - TestFrame.this.startTime;
// animation time dependent
g.fillRect((int) (timeDiff / 100), 10, 10, 10);
}
}
public class MainLoop implements Runnable {
@Override
public void run() {
while (true) {
// trigger repaint
TestFrame.this.repaint();
}
}
}
public static void main(String[] args) {
new TestFrame();
}
public TestFrame() {
// init window
this.setTitle("Test");
this.setSize(500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new MainPanel());
this.setVisible(true);
// start render loop
Thread loop = new Thread(new MainLoop());
loop.start();
}
}
问题是动画不干净,框跳转(有时)几个像素。我已经做过一些研究,根据它们,如果使用paintComponent(而不是paint)并进行基于时间的动画(不基于帧),它应该可以正常工作。我做了两个,但动画仍然不干净。
有人能给我一个暗示出了什么问题吗?
答案 0 :(得分:2)
你应该给你的while-true-loop稍微休息一下。你有点燃烧你的CPU!你正在制作大量的油漆事件;在线程调度程序决定的某个时间,调度程序切换到事件调度线程,据我所知,可能会将您的绘制事件的trillon折叠成一个并最终执行paintComponent。
在以下示例中,线程休眠20ms,最大帧速率为50fps。那应该够了。
while (true) {
// trigger repaint
TestFrame.this.repaint();
try {
Thread.sleep(20);
} catch(InterruptedException exc() {
}
}
答案 1 :(得分:0)
你在我的机器上的绘画相当流畅,但它在那个循环中燃烧了很多性能,但在较慢的机器上,我可以想象如果你的应用程序忙于执行while或处理paint事件而动画是跳跃的渲染。
根据每次渲染经过多长时间更新位置可能更好,我不确定通过Date
个对象比较动画时间的准确程度,因此使用{比较小的时差{1}}可能会更好。例如:
System.nanoTime()
答案 2 :(得分:0)
我对您的代码进行了一些更改。
我调用了SwingUtilities invokeLater方法来创建和使用Event Dispatch thread上的Swing组件。
我调用了系统currentTimeinMillis方法来获取当前时间。
我没有设置JFrame大小,而是设置了JPanel的大小并打包了JFrame。我缩小了JPanel的大小以加快重新绘制。
我在while(true)循环中添加了一个延迟,正如fjf2002在他的回答中所建议的那样。
以下是经过修改和格式化的代码:
package com.ggl.testing;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestFrame extends JFrame {
private static final long serialVersionUID = 272649179566160531L;
protected long startTime = System.currentTimeMillis();
public class MainPanel extends JPanel {
private static final long serialVersionUID = 5312139184947337026L;
public MainPanel() {
this.setPreferredSize(new Dimension(500, 30));
}
@Override
protected void paintComponent(Graphics g) {
// calculate elapsed time
long currentTime = System.currentTimeMillis();
long timeDiff = currentTime - TestFrame.this.startTime;
// animation time dependent
g.fillRect((int) (timeDiff / 100), 10, 10, 10);
}
}
public class MainLoop implements Runnable {
@Override
public void run() {
while (true) {
// trigger repaint
TestFrame.this.repaint();
try {
Thread.sleep(20L);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestFrame();
}
});
}
public TestFrame() {
// init window
this.setTitle("Test");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new MainPanel());
this.pack();
this.setVisible(true);
// start render loop
Thread loop = new Thread(new MainLoop());
loop.start();
}
}