0

SwingUtilities.invokeLater: Вызов кода в потоке событий Swing

11

У меня возник вопрос, касающийся SwingUtilities.invokeLater. Когда следует его использовать? Нужно ли применять его каждый раз, когда я обновляю компоненты GUI? Что именно он делает? Существует ли альтернатива, так как это не кажется интуитивно понятным и добавляет, по всей видимости, ненужный код?

4 ответ(ов)

0

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

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

Swing по сути не является потокобезопасным. То есть, все взаимодействия с этим API должны выполняться в одном потоке (в потоке EDT). Если вам нужно обновить GUI из другого потока (поток таймера, сетевой поток и т.д.), вы должны использовать такие методы, как тот, который вы упомянули (SwingUtilities.invokeLater, SwingUtilities.invokeAndWait и т.д.).

0

Каждое Swing-приложение имеет как минимум два потока:

  1. Основной поток, в котором выполняется приложение.
  2. EDT (Event Dispatching Thread) — это поток, который обновляет пользовательский интерфейс (UI), чтобы избежать его зависания.

Если вы хотите обновить пользовательский интерфейс, вы должны выполнять код в рамках EDT. Для этого существуют методы, такие как SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, EventQueue.invokeLater и EventQueue.invokeAndWait, которые позволяют вам выполнять код в EDT.

0

Ваш вопрос связан с SwingUtilities.invokeLater: когда следует его использовать?

Ключевое, что нужно понять, это то, что в Java есть отдельный поток (EDT), который обрабатывает события, связанные с Swing.

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

На этом все для большинства приложений.


Должен ли я использовать его каждый раз, когда мне нужно обновить компоненты GUI? Что он именно делает?

Нет. Если вы изменяете компонент GUI, это вызовет событие, которое будет зарегистрировано для последующей обработки в Swing. Если для этого события есть слушатель, поток EDT вызовет его в дальнейшем. Вам не нужно использовать invokeLater(), просто правильно установите своих слушателей на компоненты.

Имейте в виду, что этот поток — это тот же поток, который рисует кадры и т.д. на вашем экране. Поэтому слушатели не должны выполнять сложные/долгие/ресурсозатратные задачи, иначе ваш экран заморозится.


Существует ли альтернатива, так как это не звучит интуитивно и добавляет, казалось бы, ненужный код?

Вам не нужно писать больше кода, чем просто отобразить ваше приложение с помощью invokeLater() + слушатели, которые вас интересуют на компоненте. Остальное обрабатывает Swing.

0

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь