Вопрос

Я использовал следующий подход для создания компонентов и возврата значений из 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. Есть ли более простой способ сделать это?
Это было полезно?

Решение

  • Проглатывание исключений, даже не регистрируя их: плохо!! - вы возненавидите себя, когда наткнетесь на что-то подобное после 2-часового поиска ошибок
  • Нет, массив - это не очень хороший способ;во-первых, он не предлагает простого способа для вызывающего кода дождаться, пока поток EDT выполнит Runnable перед получением результата
  • Есть класс, разработанный явно для такого рода вещей: SwingWorker

Другие советы

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

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

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

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

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

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

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
  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;
}

Вы можете легко проверить, является ли текущий поток 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];
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top