SwingUtilities.invokeLater () зачем это нужно?

Почему необходимо помещать код обновления графического интерфейса в SwingUtilities.invokeLater () ?

Почему нельзя позаботиться о его внутреннем уходе? от самого свинга? Почему вызывающий должен заботиться о том, как Swing обрабатывает обновления пользовательского интерфейса?

44
задан Mikk 29 September 2013 в 18:37
поделиться

6 ответов

Объекты Swing не являются потокобезопасными . SwingUtilities.invokeLater () позволяет выполнить задачу в некоторый более поздний момент времени, как следует из названия; но что более важно, задача будет выполняться в потоке отправки событий AWT. При использовании invokeLater задача выполняется асинхронно; есть также invokeAndWait , который не вернется, пока задача не завершит выполнение.

Некоторую информацию о решении не делать Swing потокобезопасным можно найти здесь: Многопоточные инструменты: неудачная мечта?

41
ответ дан 26 November 2019 в 22:08
поделиться

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

См. Concurrent in Swing в руководстве по Java для получения дополнительных сведений. Он также ссылается на эту запись в блоге о том, почему сложно написать многопоточный инструментарий GUI.

5
ответ дан 26 November 2019 в 22:08
поделиться

Поскольку обновления графического интерфейса должны выполняться в потоке отправки событий. Если вы работаете в другом потоке, выполнение обновления в invokeLater выдергивает его из вашего потока в поток событий.

Дополнительные объяснения здесь: http://www.oracle.com/technetwork/java/painting-140037.html

Умная вещь, связанная с большими обновлениями (например, повторное заполнение JTable из базы данных) на Swing - это получить базовую модель, выполнить обновления модели в вашем потоке, а затем запустить уведомление с помощью invokeLater . Это заставляет ваш графический интерфейс реагировать на события и перерисовывать. Если обновление будет очень обширным, вы можете даже запускать эти уведомления с помощью invokeLater через равные промежутки времени во время обновления, например, каждую секунду или две.

16
ответ дан 26 November 2019 в 22:08
поделиться

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

Если вы вызовете метод, связанный с "рисованием" (paint, update, paintComponent, show, setVisible, pack и т.д.) вне EDT, вы будете пытаться рисовать в двух разных потоках, что может привести к проблемам.

Когда вам нужно использовать другой поток для обновления пользовательского интерфейса, вы должны вызвать его с помощью функции invokeLater, которая, в свою очередь, поместит его в EDT для вас, так что вы по-прежнему будете рисовать в том же потоке.

Вам не нужно его использовать, если вы кодируете в методе, который уже выполняется в EDT (например, actionPerformed или paint или один из них). Или если вы выполняете код, не связанный с UI (например, обработка файлов в фоновом режиме и т.д.)

Чтобы лучше понять все эти концепции, прочитайте:Правило одного потока

3
ответ дан 26 November 2019 в 22:08
поделиться

Повторяя другие: Swing не является потокобезопасным, поэтому один поток должен выполнять все обновления, чтобы избежать проблем с параллелизмом. invokeLater - это метод утилиты для выполнения чего-то внутри потока обработки событий.

Почему Swing не делает это внутренне: это мое впечатление... Я думаю, потому что это было бы излишне - проверять каждое место, где происходит обновление. Это раздуло бы код Swing, затруднило бы просмотр и сопровождаемость кода.

С другой стороны, не так уж сложно для приложения узнать, что оно не выполняется внутри потока GUI и вызвать invokeLater. Это произойдет, если собственное приложение запустило какой-то поток раньше.

1
ответ дан 26 November 2019 в 22:08
поделиться

Swing является однопоточным. Каждое обновление пользовательского интерфейса должно происходить из так называемого EDT — потока диспетчера событий, который является основным потоком графического интерфейса пользователя Swing (и, я думаю, AWT). Если вы этого не сделаете, то могут или произойдут странные вещи (хотя здесь мне больше нравится Windows FORms, которая просто выдает исключение, если вы делаете это неправильно).

При этом вам не нужно оборачивать каждую операцию пользовательского интерфейса в SwingUtilities.invokeLater() — если код, который вы пишете, уже выполняется EDT, в этом нет необходимости. Так что ActionListener для нажатия кнопки это не нужно. А слушатель на внешнем объекте, работающий в каком-то другом потоке, который где-то обновляет JLabel — там он вам нужен.

8
ответ дан 26 November 2019 в 22:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: