Сделайте качающуюся нить, которая показывает "Подождите" JDialog
Проблема заключается в следующем:
У меня запущено приложение swing, в какой-то момент диалог требует вставить имя пользователя и пароль и нажать "ok".
Я хотел бы, чтобы пользователь, нажав "ok", применил приложение swing в следующем порядке:
- Откройте "Подождите" JDialog
- Сделайте некоторую операцию (в конечном итоге отобразите некоторые другие JDialog или JOptionPane)
- Когда он закончит с закрытием операции, "пожалуйста, подождите" JDialog
Это код, который я написал в okButtonActionPerformed():
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
//This class simply extends a JDialog and contains an image and a jlabel (Please wait)
final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false);
waitDialog.setVisible(true);
... //Do some operation (eventually show other JDialogs or JOptionPanes)
waitDialog.dispose()
}
Этот код явно не работает, потому что, когда я вызываю waitDialog в том же потоке, он блокирует все, пока я его не закрываю.
Поэтому я попытался запустить его в другом потоке:
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
//This class simply extends a JDialog and contains an image and a jlabel (Please wait)
final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
waitDialog.setVisible(true);
}
});
... //Do some operation (eventually show other JDialogs or JOptionPanes)
waitDialog.dispose()
}
Но также это не работает, потому что waitDialog не отображается сразу, но только после этого операция завершила свою работу (когда они показывают панель joption "Вы вошли в систему как..." )
Я также попытался использовать invokeAndWait вместо invokeLater, но в этом случае он выдает исключение:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
Как я могу это сделать?
Ответы
Ответ 1
Подумайте о том, как использовать SwingWorker для выполнения фоновой работы, а затем закрыть диалоговое окно в методе SwingWorker done()
или (в моих предпочтениях) в PropertyChangeListener, который добавлен в SwingWorker.
например.
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class PleaseWaitEg {
public static void main(String[] args) {
JButton showWaitBtn = new JButton(new ShowWaitAction("Show Wait Dialog"));
JPanel panel = new JPanel();
panel.add(showWaitBtn);
JFrame frame = new JFrame("Frame");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ShowWaitAction extends AbstractAction {
protected static final long SLEEP_TIME = 3 * 1000;
public ShowWaitAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent evt) {
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>(){
@Override
protected Void doInBackground() throws Exception {
// mimic some long-running process here...
Thread.sleep(SLEEP_TIME);
return null;
}
};
Window win = SwingUtilities.getWindowAncestor((AbstractButton)evt.getSource());
final JDialog dialog = new JDialog(win, "Dialog", ModalityType.APPLICATION_MODAL);
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
dialog.dispose();
}
}
}
});
mySwingWorker.execute();
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
JPanel panel = new JPanel(new BorderLayout());
panel.add(progressBar, BorderLayout.CENTER);
panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true);
}
}
Примечания:
- Ключевой концепцией является установка всего, добавление PropertyChangeListener, запуск SwingWorker, все до отображение модального диалога, так как после отображения модального диалога весь поток кода от вызывающего кода (как вы узнали).
- Почему я предпочитаю PropertyChangeListener использовать готовый метод (поскольку Elias демонстрирует в своем достойном ответе здесь, который я проголосовал) - использование слушателя обеспечивает большее разделение проблем, ослабление связи. Таким образом, SwingWorker не должен знать ничего о коде GUI, который его использует.
Ответ 2
public void okButtonActionPerformed(ActionEvent e) {
final JDialog loading = new JDialog(parentComponent);
JPanel p1 = new JPanel(new BorderLayout());
p1.add(new JLabel("Please wait..."), BorderLayout.CENTER);
loading.setUndecorated(true);
loading.getContentPane().add(p1);
loading.pack();
loading.setLocationRelativeTo(parentComponent);
loading.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
loading.setModal(true);
SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
@Override
protected String doInBackground() throws InterruptedException
/** Execute some operation */
}
@Override
protected void done() {
loading.dispose();
}
};
worker.execute();
loading.setVisible(true);
try {
worker.get();
} catch (Exception e1) {
e1.printStackTrace();
}
}
Ответ 3
Вариант приведенного выше ответа
Это простой и воспроизводимый способ сделать...
//This code goes inside your button action
DialogWait wait = new DialogWait();
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
//Here you put your long-running process...
wait.close();
return null;
}
};
mySwingWorker.execute();
wait.makeWait("Test", evt);
//end
//Create this class on your project
class DialogWait {
private JDialog dialog;
public void makeWait(String msg, ActionEvent evt) {
Window win = SwingUtilities.getWindowAncestor((AbstractButton) evt.getSource());
dialog = new JDialog(win, msg, Dialog.ModalityType.APPLICATION_MODAL);
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
JPanel panel = new JPanel(new BorderLayout());
panel.add(progressBar, BorderLayout.CENTER);
panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true);
}
public void close() {
dialog.dispose();
}
}