Когда использовать SwingUtilies.invokeAndWait / invokeLater - PullRequest
10 голосов
/ 31 декабря 2011

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

Для базового интерфейса необходимо поставить что-то вроде new SwingGUI().setVisible(true); в строке EDT, используя invokeAndWait?Просто для отображения?

Это считается?

Ответы [ 4 ]

9 голосов
/ 31 декабря 2011

Краткий ответ на ваш вопрос: да, даже вызов на номер setVisible должен произойти на EDT.Чтобы узнать, является ли текущий поток EDT, вы можете использовать метод EventQueue#isDispatchThread

Некоторые справочные ссылки:

Редактировать: после прочтения предоставленных мною ссылокПохоже, что некоторые статьи на сайте Oracle устарели, так как они до сих пор документируют, что вы можете создавать компоненты Swing в другом потоке.На этот вопрос есть stackoverflow , который содержит несколько хороших ответов и ссылок на посты в блогах и статьи о «новой» политике (новой, как через несколько лет)

3 голосов
/ 31 декабря 2011

Да, если вы касаетесь объекта Swing, вы должны сделать это на EDT.В большинстве случаев вы уже там, но если нет, используйте классы SwingUtilities.Причина этого заключается в том, что классы Swing не являются многопоточными, поэтому вы, вероятно, вызовете неприятные проблемы, если получите доступ к ним в других потоках.И может случиться так, что setVisible() делает много вещей под одеялом, чтобы что-то отображать (например, перекладывать вещи).Лучше быть в безопасности.

0 голосов
/ 31 декабря 2011

Все, что вызывается с вашего

public static void main(String[] agrs) {

напрямую (без порождения другого потока или использования invokeLater) работает в основном потоке.

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

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

0 голосов
/ 31 декабря 2011

Все, что обращается к объектам Swing, должно делать это через поток диспетчеризации событий (EDT).Есть одно маленькое исключение из этого (которое я упомяну позже).Целью EDT является обработка любых событий, которые могут произойти из-за ввода-вывода (события мыши и клавиатуры).Довольно часто это может означать изменение макета вашего графического интерфейса.Swing не был разработан, чтобы быть потокобезопасным, а это означает, что если два потока пытаются изменить один и тот же компонент одновременно, вы можете получить поврежденный графический интерфейс.Поскольку уже существует один известный поток для доступа к компонентам Swing (EDT), никакой другой поток не должен пытаться изменять их или даже читать их состояние.

Теперь, в исключительном случае, когда вы можете манипулировать объектами Swing снаружииз EDT.Прежде чем какие-либо компоненты станут видимыми, IO не сможет инициировать события.Поэтому основной поток может настроить графический интерфейс Swing, а затем установить один JFrame, который будет видимым.Поскольку теперь в видимой рамке могут происходить события ввода-вывода, и основной поток не должен пытаться изменять какие-либо компоненты Swing.Эту опцию следует использовать только для запуска графического интерфейса, и на самом деле только с игрушечными проблемами.

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

public static void main(String[] args) {
    // create components
    JFrame f = new JFrame();
    ...

    // do layout and other bits of setup


    // show gui to user
    f.setVisible(true);
}
...