Программировать непросто, а добавление пользовательского интерфейса к функциональности действительно может усложнить жизнь. Тем более, что не все UI-фреймворки являются потокобезопасными (включая Swing). Итак, как мы можем эффективно обрабатывать пользовательский интерфейс, запускать рабочий код и обмениваться данными между ними, сохраняя при этом отзывчивость пользовательского интерфейса?
К счастью для пользователей Swing, есть несколько вариантов, которые могут значительно упростить программирование графического интерфейса пользователя. Вот два из этих вариантов.
Вызвать позже
SwingUtilities.invokeLater()
отлично подходит для обновления
пользовательского интерфейса из другого потока. Возможно, у вас есть
давно выполняемая задача, и вы хотите обновить индикатор выполнения,
чтобы предоставить пользователю обратную связь. Вы можете попробовать
что-то вроде этого:
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
progressBar.setValue(0);
progressBar.setStringPainted(true);
// Runs outside of the Swing UI thread
new Thread(new Runnable() {
public void run() {
for (i = 0; i <= 100; i++) {
// Runs inside of the Swing UI thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressBar.setValue(i);
}
});
try {
java.lang.Thread.sleep(100);
}
catch(Exception e) { }
}
}
}).start();
}
});
Надеюсь, из этого примера вы увидите, как можно использовать
SwingUtilities.invokeLater()
для связи между пользовательским
интерфейсом и рабочими потоками. Вы можете рассматривать invokeLater
как простой обратный вызов пользовательскому интерфейсу для отправки
любых необходимых вам обновлений.
Качели рабочий
SwingWorker<T,V>
можно использовать аналогично invokeLater
, но у
каждого из них есть свои сильные стороны. Лично я предпочитаю
использовать SwingWorker
для длительных задач, для которых мне не
нужно обновлять пользовательский интерфейс (например, загрузка большого
документа), в то время как invokeLater
может больше использоваться для
длительных задач, которые действительно нуждаются в обновлении
пользовательского интерфейса. SwingWorker
можно использовать таким
образом с:
private Document doc;
JButton button = new JButton("Open XML");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// All code inside SwingWorker runs on a seperate thread
SwingWorker<Document, Void> worker = new SwingWorker<Document, Void>() {
@Override
public Document doInBackground() {
Document intDoc = loadXML();
return intDoc;
}
@Override
public void done() {
try {
doc = get();
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
};
// Call the SwingWorker from within the Swing thread
worker.execute();
}
});
Этот класс разбивает рабочие события на методы, которые могут быть
реализованы в зависимости от ваших потребностей. Для более продвинутого
использования ознакомьтесь с методами publish(V... chunks)
и
process(List<V> chunks)