Java Swing Threading
Я понимаю, что если я запустил еще один поток для выполнения некоторых действий, мне нужно было бы SwingUtilities.invokeAndWait
или SwingUtilities.invokeLater
обновить графический интерфейс, пока я в указанном потоке. Пожалуйста, поправьте меня, если я ошибаюсь.
То, что я пытаюсь сделать, относительно просто: когда пользователь нажимает кнопку отправки, я хочу (перед выполнением любых действий) отключить кнопку отправки, выполнить действие и в конце действия снова включить кнопку, Мой метод для выполнения действия обновляет GUI напрямую (отображает результаты), когда он возвращает результаты.
Это действие в основном запрашивает сервер и возвращает некоторые результаты.
Что я до сих пор:
boolean isRunning = false;
synchronized handleButtonClick() {
if ( isRunning == false ) {
button.setEnabled( false );
isRunning = true;
doAction();
}
}
doAction() {
new Thread() {
try {
performAction(); // Concern A
} catch ( ... ) {
displayStackTrace( ... ); // Concern B
} finally {
SwingUtilities.invokeLater ( /* simple Runnable to enable button */ );
isRunning = false;
}
}
}
Для обеих моих проблем выше я должен использовать SwingUtilities.invokeAndWait
, так как они оба будут обновлять графический интерфейс? Все обновления графического интерфейса вращаются вокруг обновления JTextPane
. Нужно ли мне проверять поток, если я нахожусь на EDT, и если это так, я могу вызвать свой код (независимо от того, обновляет ли он GUI или нет) и НЕ использовать SwingUtilities.invokeAndWait
?
EDIT: Вот что я делаю сейчас:
handleButtonClick() {
if ( isRunning == true )
return;
disable button;
SwingWorker task = new MyTask();
task.execute();
}
...inside MyTask
doInBackground() {
return performAction();
}
done() {
result = get();
enable button;
isRunning = false;
interpret result (do most of the GUI updates here);
}
Пока performAction()
выполняет некоторые обновления графического интерфейса пользователя, я завернул их в:
if ( SwingUtil.isEDT() )
doGUIupdate()
else
SwingUtil.invokeLater( new Runnable() {
run() {
doGUIupdate();
}
} );
Надеюсь, это шаг в правильном направлении, прокомментируйте, если вы считаете, что есть лучшие способы справиться с моей ситуацией.
Ответы
Ответ 1
По-моему, вы почти никогда не должны использовать invokeAndWait()
. Если что-то займет некоторое время, что заблокирует ваш пользовательский интерфейс.
Используйте SwingWorker
для такого рода вещей. Взгляните на Улучшите производительность приложений с помощью SwingWorker в Java SE 6.
Ответ 2
Вам следует использовать SwingWorker
, поскольку он не будет блокировать поток пользовательского интерфейса, тогда как оба метода SwingUtilities
будут выполняться в потоке EDT, тем самым блокируя пользовательский интерфейс.
Ответ 3
Я сохраняю простой Thread
внутри EventQueue.invokeLater(...)
, и это работает плавно...
java.awt.EventQueue.invokeLater(new Runnable() {
public void run(){
new Thread(new Runnable(){
public void run(){
try{
EdgeProgress progress = EdgeProgress.getEdgeProgress();
System.out.println("now in traceProgressMonitor...");
while(true){
// here the swing update
if(monitor.getState() == ProgressMonitor.STATE_BUSY){
System.out.println(monitor.getPercentDone()/2);
progress.setProgress(monitor.getPercentDone()/2);
}else{
break;
}
Thread.sleep(5);
}
}catch(InterruptedException ie){}
}
}).start();
}
});