2011-02-06 6 views
1

Должен ли код обработки событий поворота быть поставлен в очередь после события на EDT? Если да, то ответственность источника события заключается в том, чтобы планировать обработчики событий, или же ответственность обработчика события заключается в том, чтобы запланировать фактический код обработки позже?Должны ли очереди обработчиков событий очереди после события на 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 принимает событие и берет на себя ответственность за код обработчика планирования после получения события (и обрабатывается всеми другими слушателями для данного типа событий). Что правильно?

EDIT: Для ясности я хочу назначить обработчики событий позже EDT, потому что изменение состояния в первом обработчике событий может скрыть исходное состояние во время события от других обработчиков событий для компонента.

ответ

1

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

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

Во-вторых, существует концепция событий, отправляемых EDT в последовательном порядке. то есть. Если событие х происходило до событий у в режиме реального времени, то обработчики событий для х должны выполняться до обработчиков событий для у. Теперь, если мой компонент, позвоните ему 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

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

+0

Да, но вопрос о ГДЕ на EDT. Компоненты могут иметь несколько прослушивателей для каждого типа события. Первый обработчик событий может изменить какое-либо состояние в компоненте gui или в другом месте, прежде чем последующие обработчики смогут проверять состояние во время запуска события. – Jesse

+2

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

1

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

+0

Чем больше я об этом думаю, тем больше я убежден, что 'SNIP 2' действительно требуется. Особенно учитывая всю идею обработчиков событий, получающих последовательность событий. Без изменения очередей в компонентах Swing на EDT вы рискуете вызвать вызовы для других обработчиков событий при работе с первым событием. То есть, конечно, если модифицированные компоненты swing не планируют новые события для последующего исполнения, на самом деле это вопрос. Я действительно опубликую полный ответ на свой вопрос после того, как я тщательно изучил это. – Jesse

+0

'SNIP 2' потребуется только в том случае, если' actionPerformed() 'должен был быть выполнен из потока, отличного от EDT. Я с нетерпением жду вашего анализа. – trashgod