Процедура задержки в Swing при нажатии кнопки, которая не должна останавливать приложение

63
7

Я пытаюсь сделать следующее: нажмите кнопку, кнопка исчезнет в течение 2 секунд, текст появится в течение 2 секунд, и после этих 2 секунд видимость будет отменена. Пока я это сделал:

btnScan.addActionListener(new ActionListener(){

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
txtScanning.setVisible(true);
btnScan.setVisible(false);
try {
Thread.sleep(2000); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
btnScan.setVisible(true);
}

});

и результат заключается в том, что, как только я нажму на btnScan, вся программа замерзает на 2 секунды, прежде чем что-либо делать. Как добавить задержку в правильном порядке?

спросил(а) 2021-01-25T17:58:39+03:00 4 месяца, 3 недели назад
1
Решение
77

Вы не должны вызывать метод сна в своем коде, который отправляет событие. Весь пользовательский интерфейс, связанный с работой, обрабатывается EDT (Event Dispatch Thread), и метод сна заставит его замерзнуть, и, следовательно, ваше приложение Swing замерзнет.

Чтобы преодолеть это, вы должны использовать таймер. Запустите таймер и выполните манипуляцию пользовательского интерфейса с помощью SwingUtilities.invokeLater, чтобы он обрабатывался с помощью EDT.

import java.util.Timer;

// make it a member variable
Timer timer = new Timer();
........
public void actionPerformed(java.awt.event.ActionEvent evt) {

button.setVisible(false);
timer.schedule(new TimerTask() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {

public void run() {
button.setVisible(true);
}
});

}
}, 2000);

}

ответил(а) 2021-01-25T17:58:39+03:00 4 месяца, 3 недели назад
46

В настоящее время в вашем коде вы вызываете EDT (поток диспетчера событий) для приостановки с вызовом Thread.sleep
Выполнение любых длительных задач в EDT приведет к зависанию пользовательского интерфейса.

Чтобы достичь желаемого, используйте поток SwingWorker для выполнения ваших действий
Это может помочь: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

ответил(а) 2021-01-25T17:58:39+03:00 4 месяца, 3 недели назад
46

Swing - это однопоточная среда, все, что блокирует этот поток, не позволит ему обрабатывать новые события, в том числе запросы на перерисовку.

Swing также не является потокобезопасным, то есть img вы никогда не должны создавать или обновлять пользовательский интерфейс вне контекста EDT.


В этом случае вы можете использовать Timer Swing для инициирования обратного вызова в будущем в будущем, которое (уведомление) будет выполняться в контексте EDT, что позволяет безопасно обновлять интерфейс пользователя с помощью

Взгляните на параллелизм в Swing и как нас развернуть таймеры для более подробной информации

ответил(а) 2021-01-25T17:58:39+03:00 4 месяца, 3 недели назад
45

Используя таймер Swing, вы можете сделать что-то вроде этого:

btnScan.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
txtScanning.setVisible(true);
btnScan.setVisible(false);
Timer timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent acv) {
btnScan.setVisible(true);
txtScanning.setVisible(false);
}
});

// setRepeats(false) to make the timer stop after sending the first event
timer.setRepeats(false);
timer.start();
}
});

ответил(а) 2021-01-25T17:58:39+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема