Как вы используете поток рассылки событий? - PullRequest
8 голосов
/ 26 октября 2011

Я узнал о том, что качание не является потокобезопасным. Углубившись глубже, я обнаружил, что каждая модификация компонента Swing должна выполняться в потоке диспетчеризации событий, чтобы предотвратить различные проблемы, связанные с многопоточностью. Однако информация, казалось, полностью остановилась на этом. Похоже, не существует хорошего учебника, который объясняет, как это сделать в любом месте, доступном в Интернете.

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

try {
        SwingUtilities.invokeAndWait(new Runnable() {

            public void run() {
                setTitle("Frame title");
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setVisible(true);

                setSize(800, 480);
                setLocationRelativeTo(null);
                setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

По сути, это правильно? Нужно ли размещать этот код (или эквивалент с invokeLater) вокруг каждой модификации компонента Swing в моем коде?

Кроме того, почему Swing не делает это автоматически?

Ответы [ 4 ]

6 голосов
/ 26 октября 2011

Хитрость в том, что когда свинг звонит вам, он всегда будет в EDT, так что вам не нужно об этом беспокоиться.

Однако, если вы находитесь в таймере или в действии, вызванном каким-либо другим внешним событием, вашим основным потоком или любым другим созданным вами потоком, тогда да, вы должны использовать invokeLater или invokeAndWait.

Другими словами, да, свинг делает «это» автоматически. Потребность в использовании invokeXx настолько редка, что если бы Swing сделал это внутренне, это потратило бы слишком много времени.

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

4 голосов
/ 26 октября 2011

обратите внимание, что любой код, выполняемый из обработчиков событий, уже запущен в EDT (Событие в аббревиатуре)

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

, и вы всегда можете запросить, если вы находитесь в EDT с SwingUtilities.isEventDispatchThread()

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

3 голосов
/ 26 октября 2011

Не весь ваш код пользовательского интерфейса должен быть частью runnable в вызове invokeLater.Это просто потому, что большая часть вашей программы все равно будет работать на EDT.Вы должны отправлять сообщения в EDT, только когда вы находитесь в другой ветке.

3 голосов
/ 26 октября 2011

По сути, вы не рисуете и не обновляете графический интерфейс извне EDT.Вы используете SwingUtilitis.invokeLater () из другого потока, чтобы гарантировать, что рисование или обновление кода GUI выполняется на EDT.

...