2010-03-08 2 views
2

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

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. Есть ли более простой способ сделать это?

ответ

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

1. Вы правы :-) 2. Хорошо, но invokeAndWait делает это. 3. Возможно, я должен использовать его, хотя для простых «геттеров» он немного переборщил. –

+0

2. О, верно, что-то не зарегистрировались. –

+2

1. SwingWorker - это не молот, который вы можете использовать, чтобы исправить все проблемы с потоками в приложениях Swing. 2. SwingWorker предназначен для работы с фоновыми потоками, но этот вопрос касается создания панели, которая должна быть запущена на EDT в любом случае - полная противоположность тому, что помогает SwingWorker. – Trejkaz

0
  1. a) Это имеет смысл. б) не то, что я знаю.
  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; 
} 
+2

В то время как 3. скорее всего работает, это, строго говоря, не разрешено. –

+1

Я согласен с Joonas, создавая компоненты Swing вне EDT, создает плохой прецедент и его следует избегать. – Nemi

3

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

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

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

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

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

Здесь, упрощенный, класс ItemHolder:

public class ItemHolder<T> { 
    public void set(T item) {...} 
    public T get() {...} 
    private T item; 
} 
+0

+1 к предложению здесь об игнорировании проблемы с потоками, так как вероятность того, что этот метод будет вызываться из EDT в любом случае. Я бы просто утвердил isEventDispatchThread() и удалил все шаблоны - задержите проблему, пока кто-то на самом деле не называет ее из другого потока, потому что YAGNI. – Trejkaz

0

Вы можете легко проверить, чтобы увидеть, если текущий поток 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]; 
    } 
} 
Смежные вопросы