2009-11-07 3 views
2

Мой текущий код выглядит следующим образом:Получение значения из компонента свинг снаружи EDT

final String[] value = new String[1]; 

SwingUtilities.invokeAndWait(new Runnable() { 
    public void run() { 
     value[0] = textArea.getText(); 
    } 
}); 

Использование конечного массива кажется немного рубить. Есть ли более элегантное решение?

Я много искал, но, похоже, я ничего не могу найти, что меня удивляет. Хотя я продолжаю сталкиваться с SwingWorker, но я не уверен, что это подходит в этом случае?

Я предполагаю, что JTextArea.getText() не является потокобезопасным.

Спасибо.

ответ

3

Все проблемы могут быть решены путем добавления другого слоя косвенности (за исключением случаев, когда у вас слишком много слоев: P).

public class TextSaver implements Runnable 
{ 
    private final JTextArea textArea; 
    private final ObjectToSaveText saveHere; 

    public TextSaver(JTextArea textArea, ObjectToSaveText saveHere) 
    { 
     this.textArea = textArea; 
     this.saveHere = saveHere; 
    } 

    @Override 
    public void run() 
    { 
     saveHere.save(textArea.getText()); 
    } 
} 

Я не собираюсь предоставлять код для ObjectToSaveText, но вы получаете идею. Тогда ваши SwingUtilties называют просто становится:

SwingUtilities.invokeAndWait(new TextSaver(textArea, saveHere)); 

Вы можете получить сохраненный текст из объекта saveHere.

+0

Ах, так что в основном просто сохранить значение в свойство объекта, а не локальную переменную? Это должно сделать трюк :) –

+0

Так что проголосуйте, пожалуйста, пожалуйста ??? : D (это мой первый ответ на вопрос cmon) – racc

+0

И да, это, вероятно, более элегантное решение, потому что вы абстрагируете задачу сохранения текста в другом классе ... – racc

1

Я нахожу, что в 99% моего кода Swing я часто обращаюсь к JTextArea в ответ на действие пользователя (пользователь набрал, нажал кнопку, закрыл окно и т. Д.). Все эти события обрабатываются через прослушиватели событий, которые всегда выполняются на EDT.

Можете ли вы предоставить более подробную информацию в вашем прецеденте?

ОБНОВЛЕНИЕ НА ОСНОВЕ ИСПОЛЬЗОВАНИЯ: Может ли пользователь изменить текст после запуска сервера? Если да, то вы можете использовать стиль слушателя, упомянутый ранее. Обязательно будьте осторожны с вашим параллелизмом. Если пользователь не может изменить текст, передайте текст в поток сервера в ответ на щелчок кнопки (который будет на EDT) и отключите текстовое поле.

последнее обновление:

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

Думаю, у вас сейчас много информации, удачи.

+0

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

+0

Не имеет смысла хранить две копии данных. Я думаю, что ваше оригинальное решение проще. – camickr

+0

Возможно, мы сможем получить более подробный ответ. Предполагая, что это какая-то настройка клиент-сервер, одна сторона опроса другого, чтобы получить текст? Какова последовательность событий? – basszero

0

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

/** 
* Executes the specified {@link Callable} on the EDT thread. If the calling 
* thread is already the EDT thread, this invocation simply delegates to 
* call(), otherwise the callable is placed in Swing's event dispatch queue 
* and the method waits for the result. 
* <p> 
* @param <V> the result type of the {@code callable} 
* @param callable the callable task 
* @return computed result 
* @throws InterruptedException if we're interrupted while waiting for the 
* event dispatching thread to finish executing doRun.run() 
* @throws ExecutionException if the computation threw an exception 
*/ 
public static <V> V getFromEDT(final Callable<V> callable) throws InterruptedException, ExecutionException { 
    final RunnableFuture<V> f = new FutureTask<>(callable); 

    if (SwingUtilities.isEventDispatchThread()) { 
     f.run(); 
    } else { 
     SwingUtilities.invokeLater(f); 
    } 

    return f.get(); 
} 

Я уверен, что вы можете понять, как использовать это, но я хотел бы показать, как особенно краток это в Java 8:

String text = <String>getFromEDT(() -> textarea.getText()); 

Edit: изменил способ сделать safe publication