Как сделать так, чтобы ImageIcon на JLabel обновлялся быстрее с меньшими задержками - PullRequest
0 голосов
/ 05 марта 2019

Я пытаюсь обновить ImageIcon на JLabel, который находится на JLayeredPane, но существует большая задержка между тем, когда поток установки отправляет правильное состояние объекту 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 байтов, так что может быть причиной задержки?Я посмотрел на ветку диспетчера событий, и многие люди говорят, что изображение должно быть мгновенным, чтобы его нарисовали.

Конечная цель: отображать на экране множество объектов-кнопок с потоком настроек, который вызывает их для обновления на основе случайных действий.Отображаемый значок для определенного объекта кнопки должен немедленно измениться, как это установлено в функции.Поток настроек не будет постоянно зацикливаться, вместо этого зацикливайтесь один раз для каждого отправленного действия (здесь дважды, чтобы показать проблему).

Любые предложения или вещи, которые можно попробовать, я протестирую, как только смогу.

Редактировать: В конце поток, который получает информацию, будет вызывать драйвер устройства в Linux, где он будет ждатьдля ответа и только когда он получит ответ, он должен будет обновить окно.Насколько я знаю, таймер используется для обновления чего-либо через равные промежутки времени, но я, вероятно, ошибаюсь.

1 Ответ

0 голосов
/ 05 марта 2019

Как объяснено в комментариях, выполняющих длинные процессы на Поток отправки событий блокирует его, поэтому он не реагирует на изменения.Также вы не должны обновлять компоненты Swing из других (не EDT) потоков.Вам необходимо использовать инструменты Swing, такие как SwingWorker или Таймер .Следующий mcve демонстрирует простое слайд-шоу с использованием таймера:

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);
    }
}
...