Качать:Есть ли способ отличить событие ItemEvent, вызванное пользователем, от события, вызванного приложением?
Вопрос
Я работаю с полем со списком в приложении на основе Swing, и мне трудно понять, что делать, чтобы отличить ItemEvent, созданный из пользовательского события, от события, вызванного приложением.
Например, допустим, у меня есть поле со списком: 'combo
' и я слушаю события itemStateChanged с помощью моего ItemListener, 'listener
'.Когда пользователь меняет выбор на элемент 2 или я выполняю строку (псевдокод):
combo.setSelection(2)
..кажется, я не могу отличить эти события друг от друга.
Тем не менее, я ни в коем случае не эксперт по Swing, поэтому решил спросить.
Спасибо!
Решение
Закон действия и противодействия вполне ясен :).Если вы попытаетесь отреагировать на изменения, нет необходимости различать пользователя и приложение.Я могу себе представить только один вариант использования, где нужно «отличить».Случай, когда приложение отображает некоторые данные.В этом случае у вас, вероятно, есть модель данных для вашего приложения.А также в этой модели есть некоторые прослушиватели изменений, и графический интерфейс приложения будет реагировать, устанавливая значения для компонентов.А также.Если пользователь выбирает что-либо в компоненте графического интерфейса.Модель данных отреагирует изменением значения.В этом случае легко настроить в модели данных какое-то состояние «только для чтения», которое будет уведомлять модель о необходимости игнорировать ЛЮБОЕ событие, исходящее от наблюдаемых объектов.Этот набор уведомлений должен работать в EDT, и с пометкой проблем не возникнет.Небольшой пример:
class ApplicationDataModel {
private Flag current = Flag.RW;
public void setData(ApplicationData data) {
current = Flag.RO;
setDataImpl(data);
notifyObservers();
current = Flag.RW;
}
public void reaction(Event e) {
if (flag = Flag.RO) return;
...
}
}
Будьте осторожны с пометкой и не забывайте о многопоточности.Если вы вызываете setData из другого потока, тогда EDT у вас возникнут проблемы.Конечно.Добыча ApplicationData
объект должен быть запущен в другом потоке;).В общем, переосмыслите дизайн своего приложения.
Другие советы
Независимо от того, выбирает ли пользователь элемент 2 или API вызывает setSelection(2), событие будет выглядеть так же.
Решение вашей проблемы может заключаться в переосмыслении того, что вы хотите, чтобы код itemStateChanged делал при изменении выбора.Почему ваше приложение будет работать по-разному при каждом условии?Возможно, есть сходства, которые вы можете использовать в своих интересах.
Будьте осторожны при использовании флагов.Событие itemStateChanged произойдет в потоке диспетчеризации событий, который отличается от того, в котором вы установили состояние флага.Это будет означать, что использование флага не может быть на 100% надежным.
Вы можете установить флаг в своем коде перед установкой выбора, а затем проверить наличие этого флага в прослушивателе (и снять флаг, если он установлен)...
Возможно, со времен Java 6 есть лучший способ, но я всегда делал это именно так...
[Редактировать]:Как указывает Дэвид, вам нужно будет установить флаг (и обновить комбинацию) в EDT, используя SwingUtilities.invokeLater или аналогичный (вам все равно следует это сделать, поскольку вы меняете элемент управления пользовательского интерфейса).
Если вам нужно различить события, возможно, в вашем дизайне есть что-то, что нужно переосмыслить.Вся суть MVC заключается в том, чтобы отделить изменения модели от реальных щелчков мыши пользователя.
Возможно, вам следует переформулировать вопрос с точки зрения почему вам когда-нибудь захочется провести различие между этими двумя ситуациями.Затем мы могли бы дать некоторые рекомендации по другому пути достижения цели.
Итак, я предполагаю, что вы хотите, чтобы выбор пользователя выполнял какое-то действие, а не просто старое прямое изменение состояния.Это проблема, вызванная ограниченной гибкостью (гибкость всегда будет ограничена, особенно если у вас есть гибкость в других направлениях).
Мое предложение:
Во-первых, всегда сразу переходите к использованию модели в Swing.Виджеты слишком сложны, и вы хотите, чтобы разные задачи были разделены.К счастью, Swing уже предлагает свои модели.
Распространенной практикой является делегирование между моделями.Итак, в этом случае у вас есть «настоящая» модель по умолчанию, в которой хранятся ваши данные.Вставьте между JComboBox и реальной ComboBoxModel и делегируйте ComboBoxModel, который выполняет действия по инструкциям по изменению состояния.Код вашего приложения должен игнорировать JComboBox и сразу перейти к реальной ComboBoxModel, минуя модель делегирования.Итак, на схеме:
User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code