如何使 JLabel 上的 ImageIcon 更新更快,延迟更少

我正在尝试更新位于 JLayeredPane 上的 JLabel 上的 ImageIcon,但是在设置线程将正确状态发送到 JLabel 对象和 GUI 显示正确状态的 ImageIcon 之间存在很多延迟。以下代码是该问题的示例,请查看按钮的打印打开/关闭与显示的图标变亮/变暗之间的时间差异。设置线程:


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 字节,那么可能导致延迟的原因是什么?我查阅了 Event Dispatcher Thread,许多人说绘制图像应该是即时的。


最终目标:屏幕上有许多按钮对象,设置线程根据随机发生的动作调用它们进行更新。特定按钮对象的显示图标应立即更改,因为它在函数中设置。设置线程不会一直循环,而是为每个发送的动作循环一次(这里是两次只是为了显示问题)。


任何建议或尝试的事情我都会尽快测试。


编辑:最后,获取信息的线程将调用 Linux 中的设备驱动程序,在那里它将等待响应,只有当它得到响应时才需要更新窗口。据我所知,计时器用于定期更新某些内容,但我可能错了。


千万里不及你
浏览 104回答 1
1回答

皈依舞

正如在The Event Dispatch Thread上运行长进程的评论中所解释的那样,它会阻塞它,因此它不会响应更改。此外,您不应该从其他(不是 EDT)线程更新 Swing 组件。您需要使用 Swing 工具,例如SwingWorker或Timer。下面的mcve演示了一个使用 Timer 的简单幻灯片: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);    }}https://i.stack.imgur.com/rTYb0.gif
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java