Swing: есть ли способ различить вызванный пользователем ItemEvent и вызванный приложением? - PullRequest
3 голосов
/ 07 октября 2008

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

Например, допустим, у меня есть поле со списком 'combo', и я слушаю события itemStateChanged с моим ItemListener, 'listener'. Когда либо пользователь изменяет выбор на элемент 2, либо я выполняю строку (псевдокод):

combo.setSelection(2)

.. похоже, я не в состоянии отличить эти события друг от друга.

Тем не менее, я ни в коем случае не являюсь экспертом по Swing, поэтому я решил спросить.

Спасибо!

Ответы [ 5 ]

2 голосов
/ 07 октября 2008

Закон действия и реакции вполне понятен :). Если вы пытаетесь реагировать на изменения, нет необходимости различать пользователя и приложение. Я могу представить только один вариант использования, где нужно «различать». Случай, когда приложение отображает некоторые данные. В этом случае у вас есть, вероятно, модель данных для вашего приложения. Кроме того, в этой модели есть слушатель изменений, и графический интерфейс приложения будет реагировать, устанавливая значения для компонентов. А также. Если пользователь выбирает что-либо в компонент GUI. Модель данных будет реагировать на изменение значения. В этом случае легко установить какое-либо состояние только для чтения в модели данных, которое уведомит модель, чтобы она игнорировала ЛЮБОЕ событие, исходящее от наблюдаемых объектов. Этот набор уведомлений должен работать в 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 голосов
/ 07 октября 2008

Независимо от того, выбирает ли пользователь элемент 2 или API вызывает setSelection (2), событие будет выглядеть так же .

Решением вашей проблемы может быть переосмысление того, что вы хотите, чтобы код itemStateChanged делал при изменении выбора. Почему ваше приложение работает по-разному при каждом условии? Возможно, есть сходства, которые вы можете использовать в своих интересах.

Будьте осторожны при использовании флагов . Событие itemStateChanged будет происходить в потоке диспетчеризации событий, который отличается от потока, в котором вы устанавливаете состояние флага. Это будет означать, что использование флага может быть ненадежным на 100%.

0 голосов
/ 07 октября 2008

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

Мое предложение:

Во-первых, всегда переходите прямо к использованию модели в Swing. Виджеты очень сложны, и вы хотите, чтобы различные проблемы были разделены. К счастью, Swing уже там со своими моделями.

Распространенным шаблоном является делегирование между моделями. Так что в этом случае у вас есть «настоящая» модель по умолчанию, которая содержит ваши данные. Вставить между JComboBox и реальной ComboBoxModel и делегировать ComboBoxModel, который выполняет действия с инструкциями по изменению состояния. Код вашего приложения должен игнорировать JComboBox и идти прямо к реальной ComboBoxModel, минуя делегирующую модель. Итак, на диаграмме:

User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code
0 голосов
/ 07 октября 2008

Если вам нужно рассказать о событиях отдельно, то, вероятно, в вашем дизайне есть что-то, что требует переосмысления. Весь смысл MVC состоит в том, чтобы отделить изменения в модели от реальных щелчков мыши пользователем.

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

0 голосов
/ 07 октября 2008

Вы можете установить флаг в своем коде, прежде чем установить выбор, а затем проверить этот флаг в слушателе (и сбросить флаг, если он установлен) ...

Может быть, лучший способ, начиная с Java 6, но я всегда так делал ...

[Редактировать] : Как указывает Дэвид, вам нужно установить флаг (и обновить комбо) в EDT, используя SwingUtilities.invokeLater или аналогичный (вы должны сделать это в любом случае, так как изменение элемента управления пользовательского интерфейса)

...