Как запросить диалоговое окно с подтверждением в середине потока не событий - PullRequest
5 голосов
/ 20 января 2011

У меня есть следующее fun, которое будет выполнено потоком не события.В середине потока я хочу всплывающее окно подтверждения

  1. .Поток приостанавливает выполнение.
  2. Пользователь делает выбор.
  3. Поток получит выбор и продолжит выполнение.

Однако я обнаружил, что это нелегкосделайте это безопасным способом потока, поскольку диалоговое окно должно быть показано потоком диспетчеризации событий.Я пытаюсь

public int fun()
{
    // The following code will be executed by non event dispatching thread.
    final int choice;
    SwingUtilities.invokeAndWait(new Runnable() {

        @Override
        public void run() {
            // Error.
            choice = JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
        }            
    });
    return choice;
}

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

Как правильно достичьвышеуказанные 3 цели?

Ответы [ 6 ]

5 голосов
/ 20 января 2011

Вы пробовали:

public int fun()
{
    // The following code will be executed by non event dispatching thread.
    final int[] choice = new int[1];
    SwingUtilities.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            // Error.
            choice[0] = JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
        }            
    });
    return choice[0];
}
2 голосов
/ 20 января 2011

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

Когда вы делаете JOptionPane, showMessge () ваш поток (Thread.currentThread ()) собирается выполнить wait (), и появится диалоговое окно.Используйте результат после showMessage, и все готово.

Таким образом:
choice = JOptionPane.showConfirmDialog(this, message, title, JOptionPane.YES_NO_OPTION);

2 голосов
/ 20 января 2011
public int fun() throws InterruptedException, InvocationTargetException {
    // The following code will be executed by non event dispatching thread.
    ChoiceRunnable runabble = new ChoiceRunnable();
    SwingUtilities.invokeAndWait(runabble);

    return runabble.choice;
  }

  class ChoiceRunnable implements Runnable {
    private int choice;

    public void run() {
      choice = JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
    }
  }
1 голос
/ 21 июля 2012

Я немного устал от того, что люди говорят так или иначе, но на самом деле не знают, о чем говорят. Я пришел сюда, задаваясь вопросом, какой поток JOptionPane должен быть запущен, но я получаю противоречивые ответы без каких-либо реальных доказательств в поддержку какой-либо из этих точек. Ну, я исследовал это сам, и я очень доволен этим ответом, поэтому я поделюсь.

Вызов одного из showXXXDialog () из JOptionPane является BLOCKING, пока пользователь не выберет ok / cancel / etc. Как правило, такие медленные блокирующие потоки не помещаются в поток диспетчеризации событий (EDT), как правило, потому что все остальные компоненты графического интерфейса будут зависать. Таким образом, инстинктивный инстинкт не помещать это в EDT хорош, но это также неправильно. Причина в том, что, как утверждают некоторые другие, метод создает компоненты GUI, и это всегда должно быть сделано в EDT. Но как насчет блокировки? Вы заметите, что даже если вы запустите его на EDT, он работает нормально. Причина находится внутри исходного кода. Класс JOptionPane создает объект Dialog, а затем вызывает show (), а затем dispose (), первым из которых является то, что блокирует поток. Если вы прочтете комментарии (или javadoc), вы увидите, что это говорит о методе:

Если диалоговое окно является модальным и не отображается, этот вызов не будет возвращайтесь, пока диалог не будет скрыт, вызывая hide или dispose. это допускается показ модальных диалогов из потока диспетчеризации событий потому что инструментарий будет гарантировать, что еще один насос событий работает в то время как тот, который вызвал этот метод, заблокирован.

Итак, совершенно безопасно запускать JOptionPane на EDT, несмотря на его блокировку. Очевидно, что безопасно вызывать метод Dialog show () из EDT, но то же самое нельзя сказать о JOptionPane, потому что его методы создают компоненты GUI, добавляют слушатели, обращаются к другим контейнерам при модальном и блокируют ввод данных и т. Д. Вы не делаете этого. Я хочу, чтобы все это было сделано вне EDT, потому что оно не поточно-ориентированное и могут возникнуть проблемы. Правда, я никогда не видел проблем при использовании JOptionPane вне EDT, и поэтому шансы кажутся низкими, но они, безусловно, возможны. Передача null для контейнера диалога и предоставление только неизменяемых объектов (таких как Strings) в качестве аргументов для полей значительно уменьшит (возможно, даже устранит, насколько я знаю) вероятность чего-то плохого, потому что все соответствующие компоненты GUI сделаны и доступны в той же теме, пока они не видны. Но вы должны просто быть в безопасности и поставить его на EDT. Нетрудно вызвать SwingUtilities.invokeAndWait ().

1 голос
/ 20 января 2011

Может быть, я не понимаю вопроса, но я также не получаю ответы ... если вы хотите, чтобы вызывающий поток блокировал вызов fun (), зачем отображать JOptionPane в новом (параллельном) потоке ? Разве этого не достаточно?

public int fun() {
    return JOptionPane.showConfirmDialog(null, message, title, JOptionPane.YES_NO_OPTION);
} 

PS Как вы определяете поток, не связанный с событиями?

0 голосов
/ 05 октября 2017

Запустите JOptionPane из EDT и передайте значение обратно с помощью FutureTask.

public int fun()
{
    FutureTask<Integer> dialogTask = new FutureTask<Integer>(new Callable<Integer>() 
    {
        @Override public Integer call() 
        {
            return JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
        }
    });
    SwingUtilities.invokeLater(dialogTask);
    int choice  = dialogTask.get();
}

Кредит в пользу jtahlborn Как передать результаты из EDT обратно в другой поток?

...