Должны ли обработчики событий колебания ставиться в очередь после события в EDT? - PullRequest
1 голос
/ 06 февраля 2011

Должен ли код обработки события колебания ставиться в очередь после события в EDT? Если да, то несет ли ответственность источник событий за планирование обработчиков событий или же за обработчик событий отвечает за планирование фактического кода обработки позже?

Рассмотрим:

JButton b = new JButton();
b.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e){
        /*
         * SNIP 1
         * do something that may affect other
         * components or generate new events...
         */

        // SNIP 2
        EventQueue.invokeLater(new Runnable(){
            public void run(){
                /*
                 * do something that may affect other
                 * components or generate new events...
                 */
            }
        });
    }
});

SNIP 1 запускает код обработчика при получении события. Если JButton берет на себя ответственность за планирование события на EventQueue.invokeLater(), то это, вероятно, правильно. SNIP 2 получает событие и берет на себя ответственность за планирование кода обработчика после получения события (и обработки всеми другими слушателями для этого конкретного типа события). Что правильно?

РЕДАКТИРОВАТЬ: просто для ясности, я хочу запланировать обработчики событий позже на EDT, потому что изменение состояния в первом обработчике события может скрыть исходное состояние во время события от других обработчиков событий для компонента.

Ответы [ 3 ]

1 голос
/ 06 февраля 2011

Как отмечает @HFOE, элементы в EventQueue являются последовательными и упорядоченными ; SNIP 2 не требуется. Если я понимаю ваше требование, одним из подходов может быть пересылка события любому другому заинтересованному слушателю (ям), как это предлагается в этом вопросе и ответе .

1 голос
/ 07 февраля 2011

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

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

Во-вторых, существует концепция событий, отправляемых EDT в последовательном порядке. то есть. Если событие x произошло до события y в режиме реального времени, тогда обработчики событий для x должны выполняться перед обработчиками событий для y . Теперь, если мой компонент, давайте назовем его c1 , имеет 2 обработчика событий для события actionPerformed() - eh1 и eh2 . Когда actionPerformed() срабатывает c1 , eh1 вызывается для обработки события. Затем он изменяет компонент c2 и вызывает событие itemStateChanged() для c2 . Поскольку это изменение было поставлено в очередь после завершения первого события actionPerformed() (позднее по EDT), а также потому, что c2 не ставит в очередь событие itemStateChanged() для последующего запуска в EDT, событие itemStateChanged() обрабатываются всеми его слушателями. Только тогда второй actionPerformed() слушатель ( eh2 ) сможет обработать исходное событие actionPerformed().

Если eh2 также был прослушивателем itemStateChanged() событий для компонента c2 , то eh2 может показаться, что событие itemStateChanged() действительно произошло до события actionPerformed(). Это тоже, безусловно, не так.

Таким образом, это отвечает на вопрос 1. Да, код обработки событий, который изменяет состояние приложения или дерево компонентов , должен быть запланирован для выполнения после обработки события. Обработчики событий должны проверять любое состояние, которое они должны проверять во время события, но реагировать на событие (вносить изменения) позже в EDT, вызывая EventQueue.invokeLater().

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

Между прочим, когда я исследовал это, я увидел, что не все компоненты Swing делают это равномерно. Например, JCheckBox запускает события itemStateChanged() сразу же, когда событие происходит, в то время как JComponent запускает componentResized() (через суперкласс java.awt.Component) позже в EDT.

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

1 голос
/ 06 февраля 2011

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

...