Правильное обновление компонентов свинга - PullRequest
5 голосов
/ 13 марта 2012

Я устанавливал значения для компонентов Swing так же, как и для любой другой переменной, однако я наткнулся на эту страницу - https://bitguru.wordpress.com/2007/03/21/will-the-real-swing-single-threading-rule-please-stand-up/ - и, похоже, я делаю все изменения в компонентах Swing, используя поток диспетчеризации событий. -

Итак, это правильно, я должен изменить весь код, где я обновил компоненты Swing с этого

    String name = this.getNameTextfield().getText();
    String password = new String(this.getPasswordField().getPassword());
    String confirmPassword = new String(this.getConfirmPasswordField().getPassword());

к этому?

java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
               String name = this.getNameTextfield().getText();
               String password = new String(this.getPasswordField().getPassword());
               String confirmPassword = new String(this.getConfirmPasswordField().getPassword());
            }
        });

Это стандартная практика?

Редактировать: К сожалению, просто скопировал и вставил часть моего кода, связанного с компонентами, упустил из виду тот факт, что он не обновлял компоненты.

Ответы [ 4 ]

9 голосов
/ 13 марта 2012

В библии Swing есть глава по параллелизму , нижняя строка:

весь код, который создает или взаимодействует с компонентами Swing, должен запускаться на событиипоток рассылки

(выделение мое)

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

С другой стороны: если приложение правильно запущено на EDT, вы уже на нем , и почти весь доступ, естественно, происходит на EDT.Это не так, только если вы явно запустили другой поток (например, для выполнения длительной фоновой задачи) и вам необходимо отчитаться в пользовательском интерфейсе: тогда вы должны заключить вызовы доступа в invokeLater (или использовать SwingWorker, который делает это внутренне)

4 голосов
/ 13 марта 2012

Строки являются неизменяемыми - следующие строки в значительной степени эквивалентны

String password = new String(this.getPasswordField().getPassword());
String password = this.getPasswordField().getPassword();

Вы не изменяете компоненты.

Если вы обновляли их, то только если обновление было из другого потока.Например, если вы обновляли текстовое поле из ActionListener, прикрепленного к кнопке, это было бы ненужным, поскольку вы уже находитесь в Event-Dispatch-Thread.

Для максимальной корректности вы должны определить, если вына EDT первым.

Runnable update = new Runnable() {
    @Override
    public void run() {
        getNameTextfield().setText("foo");
    }
};
if (SwingUtilities.isEventDispatchThread()) {
    update.run();
} else {
    SwingUtilities.invokeLater(update);
}
3 голосов
/ 13 марта 2012

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

1 голос
/ 13 марта 2012

Если вы просто читаете данные из компонентов, вам, вероятно, не нужно это делать. Большинство операций чтения из свойств компонента Swing являются потокобезопасными.

invokeLater следует использовать, если вы хотите запустить код в потоке диспетчеризации событий, как правило, это тот случай, когда вы действительно хотите обновить графический интерфейс.

Здесь есть короткое небольшое руководство по использованию invokeLater .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...