Диалоговое окно Swing отказывается закрываться - иногда! - PullRequest
6 голосов
/ 17 октября 2010
// This is supposed to show a modal dialog and then hide it again. In practice,
// this works about 75% of the time, and the other 25% of the time, the dialog
// stays visible.
// This is on Ubuntu 10.10, running:
// OpenJDK Runtime Environment (IcedTea6 1.9) (6b20-1.9-0ubuntu1)

// This always prints
// setVisible(true) about to happen
// setVisible(false) about to happen
// setVisible(false) has just happened
// even when the dialog stays visible.

package modalproblemdemo;

import java.awt.Frame;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;

public class Main {
    public static void main(String[] args) {
        final Dialogs d = new Dialogs();
        new Thread() {
            @Override
            public void run() {
                d.show();
                d.hide();
            }
        }.start();
    }

    static class Dialogs {
        final JDialog dialog;

        public Dialogs() {
            dialog = new JDialog((Frame) null, "Hello World", /*modal*/ true);
            dialog.setSize(400, 200);
        }

        public void show() {
            SwingUtilities.invokeLater(new Runnable() { public void run() {
                dialog.setLocationRelativeTo(null);
                System.out.println("setVisible(true) about to happen");
                dialog.setVisible(true);
            }});
        }

        public void hide() {
            SwingUtilities.invokeLater(new Runnable() { public void run() {
                System.out.println("setVisible(false) about to happen");
                dialog.setVisible(false);
                System.out.println("setVisible(false) has just happened");
            }});
        }
    }
}

Ответы [ 4 ]

4 голосов
/ 17 октября 2010

Это явно какое-то состояние гонки.Я не думаю, что это так просто, как ответ Эрика Робертсона.Код show() в диалоге довольно сложный, он содержит некоторую специальную логику для вызова из потока диспетчеризации событий, а также отправляет события в очередь событий.Возможно, порядок, в котором публикуются события, каким-то образом зависит от задержек потоков.

Возможно, вам нужно SwingUtilities.invokeAndWait(), таким образом вы гарантируете, что setVisible(true) завершил выполнение до вызова setVisible(false).. Как указал Skip Head, invokeAndWait будет блокироваться до тех пор, пока диалог не будет закрыт.

И зачем он вам нужен?

РЕДАКТИРОВАТЬ: Это мой сценарий того, что происходит:

  1. Вы вызываете d.show (), который отправляет setVisible(true) событие
  2. , поток помещается в спящий режим планировщиком, и EDT запускает и начинает выполнение первого события
  3. EDT удаляется до завершения первой задачи и публикует фактическое событие, отображающее диалоговое окно
  4. , когда ваш поток выполняет d.hide (), который отправляет событие setVisible (false).Поток завершен, и EDT запускает
  5. EDT завершил первое задание, помещает свое событие показа в очередь событий
  6. Он переходит к следующему событию, и, вуаля, это setVisible (false) event!
  7. Он портит все состояние диалога и остается видимым и не отвечает.

EDIT2: похоже, ProgressMonitor обладает функциональностью, которую выпытаемся реализовать.

2 голосов
/ 09 октября 2012

Таким образом, получается, что при модальном диалоге show () / setVisible (true) происходит то, что в вызове show / setVisible запускается второй цикл диспетчеризации событий. Что имеет смысл, если вы знаете об этом. Имея это в виду, я получил следующий код:

public void runBlockingTask(final String taskName, final BlockingTask bt) {
    SwingUtilities.invokeLater(new Runnable() { public void run() {
        new Thread("Worker Thread: " + taskName) {
            @Override
            public void run() {
                bt.run();
                progressDialog.setVisible(false);
            }
        }.start();
    }});
    // NB This causes the event dispatch loop to be run inside this call,
    // which is why we need  to put everything after setVisible into an
    // invokeLater.
    progressDialog.setVisible(true);
}
1 голос
/ 18 октября 2010

Вы можете попробовать dispose() диалоговое окно вместо того, чтобы его скрывать, но для этого потребуется перестроить его, если вы захотите показать его снова.

0 голосов
/ 04 июля 2016

Небольшое время ожидания (100 мс) между setVisible (true) и setVisible (false) в некоторых случаях решает проблему. см. также https://bugs.openjdk.java.net/browse/JDK-5109571 И при попытке использовать dispose вместо setVisible (false) условие гонки не возникает

...