Возврат значений из Swing с использованием invokeAndWait - PullRequest
3 голосов
/ 08 марта 2010

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

public JPanel threadSafeAddPanel() {

    final JPanel[] jPanel = new JPanel[1];

    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }

    return jPanel[0];
}

Локальный массив 1-длины используется для передачи«результат» изнутри Runnable, который вызывается в EDT.Ну, это выглядит "немного" странно, и поэтому мои вопросы:

  1. Имеет ли это смысл?Кто-нибудь еще делает что-то подобное?
  2. Является ли массив длины 1 хорошим способом передачи результата?
  3. Есть ли более простой способ сделать это?

Ответы [ 4 ]

3 голосов
/ 09 марта 2010

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

Причина заключается в том, что создание большинства (если не всех) ваших компонентов всегда будет происходить из EDT, в результате действий пользователя (пункт меню или нажатие кнопки), которые всегда выполняются из EDT.

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

Что касается вашего вопроса 2, к сожалению, у вас не так много способов сделать это:

  • Используйте массив из 1 элемента, как вы это сделали, это самое простое, но и самое уродливое решение
  • Создать класс ItemHolder (см. ниже), что делает почти то же самое, требует немного больше работы и чище, на мой взгляд
  • Последнее, используйте java.util.concurrent объекты (Будущее и Callable); я думаю, это было бы но и это требует наибольшего усилия

Вот упрощенный класс ItemHolder:

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
1 голос
/ 08 марта 2010
  • Проглатывание исключений, даже не регистрируя их: плохо !! - вы будете ненавидеть себя, когда столкнетесь с чем-то подобным после двухчасовой охоты на ошибок
  • Нетмассив не хороший способ;с одной стороны, он не предлагает простому методу для вызывающего кода ждать, пока поток EDT не выполнит Runnable перед извлечением результата
  • . Существует класс, специально разработанный для такого рода вещей: SwingWorker
0 голосов
/ 09 марта 2010

Вы можете легко проверить, является ли текущий поток EDT, а затем выполнить правильно и проще в этом контексте. Что касается использования окончательного массива для получения возвращаемого значения, это самый простой способ, когда вам нужно использовать анонимный внутренний класс, подобный этому.

public JPanel threadSafeAddPanel() throws InterruptedException, 
        InvocationTargetException {
    if (EventQueue.isDispatchThread()) {
        JPanel panel = new JPanel();
        add(panel);

        return panel; 
    } else {
        final JPanel[] jPanel = new JPanel[1];
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });

        return jPanel[0];
    }
}
0 голосов
/ 08 марта 2010
  1. а) Это имеет смысл. б) не то, что я знаю.
  2. Как хорошо.
  3. Создание JPanel вне invokeAndWait вызова

// Эта строка добавлена ​​к уценке

public JPanel threadSafeAddPanel() {
    final JPanel jPanel = new JPanel();
    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                add(jPanel);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }
    return jPanel;
}
...