Безопасно открывать и закрывать модальный JDialog (используя SwingWorker)

Мне нужен был способ получить некоторые данные из базы данных и запретить пользователю изменять существующие данные на данный момент.

Я создал SwingWorker для обновления базы данных и модальный JDialog, чтобы показать пользователю, что происходит (с помощью JProgressBar). В модальном диалоговом окне по умолчаниюCloseOperation установлено значение DO_NOTHING, поэтому его можно закрыть только с помощью правильного вызова — я использую setVisible(false).

MySwingWorkerTask myTask = new MySwingWorkerTask();
myTask.execute();
myModalDialog.setVisible(true);

SwingWorker делает некоторые вещи внутри doInBackground() и, наконец, вызывает:

myModalDialog.setVisible(false);

Мое единственное беспокойство и мой вопрос: возможно ли, что SwingWorker выполняет setVisible(false) до того, как он будет setVisible(true) в строке после появления работника?

Если это так, setVisible(true) может заблокироваться навсегда (пользователь не может закрыть модальное окно).

Должен ли я реализовать что-то вроде:

while (!myModalDialog.isVisible()) {
    Thread.sleep(150);
}
myModalDialog.setVisible(false);

чтобы убедиться, что он действительно закроется?


person user1713059    schedule 29.10.2012    source источник
comment
Вы должны вызывать myModalDialog.setVisible(false); в done() вместо doInBackground(). Почему бы тебе не позвонить setVisible(true) перед execute?   -  person assylias    schedule 30.10.2012
comment
setVisible(true) — блокирующий вызов   -  person user1713059    schedule 30.10.2012
comment
Ха-ха - действительно хорошая мысль :-)   -  person assylias    schedule 30.10.2012
comment
Чтобы быстрее получить помощь, опубликуйте SSCCE.   -  person Andrew Thompson    schedule 30.10.2012
comment
Хорошо, я попробую еще раз. Спасибо за совет done().   -  person user1713059    schedule 30.10.2012


Ответы (1)


Как правило, да.

Я бы сделал так: в вашем методе doInBackground используйте SwingUtilities.invokeLater для отображения диалогового окна, а в вашем методе done скройте диалоговое окно.

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

Незначительная проблема заключается в том, что теперь вам придется передать диалог рабочему, чтобы он мог получить над ним контроль...

public class TestSwingWorkerDialog {

    public static void main(String[] args) {
        new TestSwingWorkerDialog();
    }
    private JDialog dialog;

    public TestSwingWorkerDialog() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                MyWorker worker = new MyWorker();
                worker.execute();

            }
        });
    }

    public class MyWorker extends SwingWorker<Object, Object> {

        @Override
        protected Object doInBackground() throws Exception {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    getDialog().setVisible(true);
                }
            });
            Thread.sleep(2000);

            return null;
        }

        @Override
        protected void done() {
            System.out.println("now in done...");
            JDialog dialog = getDialog();
            // Don't care, dismiss the dialog
            dialog.setVisible(false);
        }

    }

    protected JDialog getDialog() {
        if (dialog == null) {

            dialog = new JDialog();
            dialog.setModal(true);
            dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
            dialog.setLayout(new BorderLayout());
            dialog.add(new JLabel("Please wait..."));
            dialog.setSize(200, 200);
            dialog.setLocationRelativeTo(null);

        }

        return dialog;
    }

}
person MadProgrammer    schedule 30.10.2012
comment
В чем разница между SwingUtilities.invokeLater и EventQueue.invokeLater? - person Mordechai; 30.10.2012
comment
Извините, если мой вопрос глупый, но в вашем примере гарантируется, что метод запуска invokeLater обязательно запустится до того, как работа будет выполнена ()? Мне кажется, что основная проблема моего поста остается - теоретически неопределенный параллелизм, но я могу ошибаться. - person user1713059; 30.10.2012
comment
@М.М. Их нет. SwingUtilities.invokeLater перенаправляет вызов в EventQueue.invokeLater. - person Guillaume Polet; 30.10.2012
comment
@user1713059 user1713059 это гарантирует, что 1. диалоговое окно будет открыто только после запуска рабочего процесса и 2. что оно не будет закрыто (или попытается закрыться) до завершения работы. Поскольку метод done выполняется в контексте EDT, используя метод, аналогичный тому, который я использовал для его открытия, событие открытия будет выполнено ДО закрытия, поскольку оно было добавлено в очередь первым. - person MadProgrammer; 30.10.2012
comment
@MadProgrammer Я не думаю, что invokeLater дает какие-либо гарантии относительно порядка выполнения вещей. - person assylias; 30.10.2012
comment
Вместо этого вы можете использовать invokeAndWait - это должно быть на 100% надежным. - person assylias; 30.10.2012
comment
@assyoias да и нет. Поскольку мы добавляем события в очередь, есть некоторая гарантия порядка, в котором они будут вызываться, что позволяет различать разницу во времени, вы правы, если у вас есть два потока, пытающихся опубликовать сообщения почти в одно и то же время, тогда это сводится к механизму синхронизации. . Не используйте invokeAndWait для вызова блокирующего фрагмента кода (если это не ваше намерение), OP пытается показать модальный диалог. В этом контексте invokeAndWait не вернется до тех пор, пока диалоговое окно не будет закрыто. - person MadProgrammer; 30.10.2012
comment
Согласен с вашей точкой зрения на invokeAndWait, но ничто в документах не говорит, что очередь fifo. - person assylias; 30.10.2012
comment
@assylias Хава прочитал EventQueue В том же порядке, в котором они стоят в очереди. - person MadProgrammer; 30.10.2012
comment
@MadProgrammer Хороший вопрос, но он также говорит обратите внимание, что события, публикуемые в EventQueue, могут быть объединены... Я запутался... - person assylias; 30.10.2012
comment
@MadProgrammer У меня есть точность в этом вопросе здесь: /swingutilities-invokelater/ - person assylias; 30.10.2012