Java 如何使JLabel上的ImageIcon更新更快,延迟更少
我试图更新位于JLayeredPane上的JLabel上的ImageIcon,但设置线程向JLabel对象发送正确状态与GUI显示正确状态的ImageIcon之间存在大量延迟。下面的代码是问题的一个示例,查找按钮打印打开/关闭与显示图标变亮/变暗之间的时间差。 设置线程:Java 如何使JLabel上的ImageIcon更新更快,延迟更少,java,multithreading,swing,jlabel,imageicon,Java,Multithreading,Swing,Jlabel,Imageicon,我试图更新位于JLayeredPane上的JLabel上的ImageIcon,但设置线程向JLabel对象发送正确状态与GUI显示正确状态的ImageIcon之间存在大量延迟。下面的代码是问题的一个示例,查找按钮打印打开/关闭与显示图标变亮/变暗之间的时间差。 设置线程: new Thread(new Runnable() { // setting thread @Override public void run() { // TODO A
new Thread(new Runnable() { // setting thread
@Override
public void run() {
// TODO Auto-generated method stub
try {
while(true) {
System.out.println("testButton on"); // print that the button is on
testButton.updateState(1); // set button state to on
Thread.sleep(70 + random.nextInt(500)); //sleep between 70 and 570 milliseconds
System.out.println("testButton off");// print that the button is off
testButton.updateState(0); // set button state to off
Thread.sleep(70 + random.nextInt(500)); // sleep between 70 and 570 milliseconds
}
} catch(Exception e) {
e.printStackTrace();
}
}
}).start();
按钮对象:
class Button extends JLabel {
ImageIcon released;
ImageIcon pressed;
String text;
public Button(int x, int y, String text) {
released = new ImageIcon("src/components/images/button.png");
pressed = new ImageIcon("src/components/images/buttonDown.png");
setBounds(x,y, 100, 100);
this.text = text;
setIcon(released);
}
public void updateState(int data) {
if (data == 1) {
setIcon(pressed);
}
else {
setIcon(released);
}
}
}
ImageIcons只有325字节,那么是什么导致了延迟呢?我查了一下事件调度器线程,很多人都说应该是瞬间图像被绘制出来的
最终目标:在屏幕上有许多按钮对象,设置线程根据随机发生的动作调用它们进行更新。特定按钮对象的显示图标应在功能中设置后立即更改。设置线程不会持续循环,而是为每个发送的操作循环一次(这里是两次,只是为了显示问题)
任何建议或尝试的事情我都会尽快测试
编辑:最后,获取信息的线程将调用Linux中的设备驱动程序,在那里它将等待响应,只有当它获得响应时才需要更新窗口。据我所知,计时器用于定期更新某些内容,但我可能是错的。正如在块上运行长进程的注释所解释的,因此它不响应更改
此外,您不需要从其他(非EDT)线程更新Swing组件。
您需要使用像或这样的Swing工具。 下面演示了使用计时器的简单幻灯片放映:
import java.awt.BorderLayout;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
public class ChangeButtonIcon extends JPanel{
private final URL[] urls = {
new URL("https://findicons.com/files/icons/345/summer/128/cake.png"),
new URL("http://icons.iconarchive.com/icons/atyourservice/service-categories/128/Sweets-icon.png"),
new URL("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS_FkBgG3_ux0kCbfG8mcRHvdk1dYbZYsm2SFMS01YvA6B_zfH_kg"),
};
private int iconNumber = 0;
private final JButton button;
private boolean stop = true;
private final Random random;
private static final int MIN_DELAY = 70, DELAY = 500;
private Timer timer;
public ChangeButtonIcon() throws IOException {
random = new Random();
button = new JButton();
button.setIcon(new ImageIcon(urls[iconNumber]));
button.setHorizontalTextPosition(SwingConstants.CENTER);
button.addActionListener(e -> startStopSlideShow());
add(button);
}
private void startStopSlideShow(){
stop = ! stop;
if(stop){
timer.stop();
return;
}
timer = new Timer( MIN_DELAY+ random.nextInt(DELAY), (e)->swapIcon());
timer.start();
}
private void swapIcon() {
iconNumber = iconNumber >= urls.length -1 ? 0 : iconNumber+1;
button.setIcon(new ImageIcon(urls[iconNumber]));
}
public static void main(String[] args) throws IOException{
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(new ChangeButtonIcon());
window.add(new JLabel("Click image to start / stop"), BorderLayout.PAGE_END);
window.pack();
window.setVisible(true);
}
}
使用Swing
计时器,而不是线程。睡眠
-Swing是单线程的,不安全。您的代码违反了Swing线程规则,这可能会导致延迟或更糟,可能会导致程序意外崩溃--不好。查看以了解这些规则的细节。