我有一个java应用程序,我正在加载3个gif文件到BuffereImage数组中,并希望显示它们。
我有一个简单的线程,使用thread.sleep()每16毫秒(约60帧/秒)执行一次
在这个方法中,我调用paintcomponent方法来绘制gui组件。但是我不希望线程(runnable)等待方法结束渲染,因为延迟超过16ms,即使它是不可测量的。
下面是我的runnable jlabel(目前是快速/高效的方法)中的一个片段
@Override
public void run() {
while (active) {
repaint(); //Takes 0ms
i++; // Counter used inside paintComponent()
Thread.sleep(speed * multiplier));
if (i + 1 == frames.length) {
i = 0;
}
}
}
@Override
public void paintComponent(Graphics g) {
g.drawImage(frames[i], 0, 0, x, y, observerFrame);
g.dispose();
}
我测试过了,重新上漆的方法需要0毫秒。可能无法测量。但这还不够精确吗?或者效率低下?
所以(简单的)数学是在线程内部完成的。但我如何确保时间的精确性呢?我的意思是它仍然足够精确,但它仍然取决于电脑的速度
在回答@reto h之后ö我做了一些研究,尝试了另一种方法。但在渲染图像时仍然效率低下且滞后(顺便说一句,BuffereImage):
这是我做的一个很大的尝试,我认为这样会更好:
Timer timer = new Timer(16, this);
Executor executor = Executors.newCachedThreadPool();
//called by executor
@Override
public void run() {
i++; // Counter used inside paintComponent()
Thread.sleep(speed * multiplier));
if (i + 1 == frames.length) {
i = 0;
}
}
//called by timer & runs on EDT
@Override
public void actionPerformed(ActionEvent e) {
repaint();
executor.execute(this); //Costs no time and has enought time to complete
}
@Override
public void paintComponent(Graphics g) {
g.drawImage(frames[i], 0, 0, x, y, observerFrame);
g.dispose();
}
所以这样我保证
重新上漆是在edt中完成的
数学是由另一个线程使用执行器完成的
即使我在编译和运行之后感到自豪,结果还是让我哭了。。。
对于第一种方法,jvm使用大约10%的cpu。一切都很好,在fps上运行的所有3帧。
第二次尝试使用较少的cpu,但性能较差。我不知道为什么,但图形用户界面是响应,但渲染速度慢了近3倍。
目标是以每秒60帧的速度渲染图像而不延迟。
这里的重点是,我尝试了一个尝试,我认为这是更好的概念,但它做得更糟。
所以我的问题是,是否有更好更精确的方法来实现这一点。否则,我将继续使用简单的基于线程的解决方案。
问候nur1
1条答案
按热度按时间szqfcxe21#
首先,稍微了解一下java事件调度线程(或awt事件队列)的概念可能会有所帮助。
我的建议是使用一个只负责调用
.repaint()
-方法。考虑使用javax.swing.Timer
为此,它已经在幕后使用了一个线程,并且能够在多个事件到达太快时合并它们。然后使用另一个只负责计算绘制所需信息的线程。一种方法是渲染到缓冲区图像。这个
.paint()
-或者.paintComponent()
-显示组件的方法只需绘制该图像。