На самом деле идея проста: вынести обработчик в отдельный поток.
Например у нас есть диалог с кнопкой запуска длительного процесса
import javax.swing.*;
public class scratch extends JDialog {
private JPanel contentPane;
private JButton begin;
private JProgressBar progressBar;
public scratch(){
setContentPane(contentPane);
setModal(true);
getRootPane().setDefaultButton(begin);
begin.addActionListener(e -> onBeginButton());
}
public static void main(String[] args) {
scratch dialog = new scratch();
dialog.pack();
dialog.setVisible(true);
System.exit(0);
}
}
Теперь в функции onBeginButton(), отвечающей за некую длительную операцию, нужно создать отдельный поток:
private void onBeginButton() {
progressBar.setValue(0);
progressBar.setMaximum(100);
begin.setEnabled(false);
Runnable worker = () -> {
try {
for (int i = 0; i <= 100; i++) {
progressBar.setValue(i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
begin.setEnabled(true);
};
new Thread(worker).start();
}
В обработчике я использовал традиционный для таких примеров sleep. Так же специально дергаю прогрес бар, что бы показать что UI поток не блокируется. Еще блокирую кнопку от повторного нажатия.
В реальном приложении обработчик вынесен в отдельный класс, который использует еще целую кучу паттернов ООП. Прогрес бар я передаю в качестве аргумента и инкрементирую в нужный момент в совершенно другом месте.