EventListenerList порядок запуска - PullRequest
8 голосов
/ 29 января 2010

В приложении Swing у меня есть несколько подпанелей, каждая из которых слушает один JSlider. Окружающая родительская панель также прослушивает все вложенные панели. Чтобы получить согласованные результаты в приведенном ниже примере, мне сначала нужно было добавить родителя и , а затем локального слушателя. Это имеет смысл, учитывая порядок, предписанный в EventListenerList и объясненный в этой статье . Могу ли я рассчитывать на этот заказ или мне следует организовать другое мероприятие?

class SubPanel extends JPanel implements ChangeListener {

    private final JSlider slider = new JSlider();
    private final JLabel label = new JLabel();
    private final String name;
    private float value;

    public SubPanel(String name, float value, ChangeListener parent) {
        this.name = name;
        this.value = value;
        ...
        slider.addChangeListener(parent);
        slider.addChangeListener(this);
    }
    ...
}

Добавление: обсуждение в EventListenerList представляется скорее рекомендацией по реализации, а не гарантией. Цепной подход, предложенный pstanton , обеспечивает более надежное выполнение правильного порядка. Например, SubPanel ChangeListener может просто переслать событие родителю.

    @Override
    public void stateChanged(ChangeEvent e) {
        ...
        parent.stateChanged(e);
    }

Ответы [ 2 ]

4 голосов
/ 29 января 2010

Поскольку в документации для JSlider, JComponent и т. Д. Не указан порядок уведомления слушателя, я бы не стал полагаться на него, по крайней мере без тщательного тестирования каждой последующей версии JRE.

Если вам действительно нужно положиться на порядок, рассмотрите возможность создания цепочки слушателей, т.е. слушатель один уведомит слушателя два и т. Д.

1 голос
/ 23 октября 2013

Немного стар и очень поздно, чтобы ответить. Но мой неустойчивый ум действительно заставляет меня суетиться.

Могу ли я рассчитывать на этот заказ или я должен отправить другое событие?

Я верю, что они поддерживают порядок, документация Компонента нам мало что говорит, но исходный код всегда наш друг. Давайте начнем с addChangeListener(listener) функции JSlider:

ШАГ 1: вызов jSlider.addChangeListener(listener) добавляет listener к listener list.

public void addChangeListener(ChangeListener l) {
        listenerList.add(ChangeListener.class, l);
    }

ШАГ 2: исходный код EvenListenerList: synchronized add(Class<T> t, T l): добавляет слушателей и соответствующий тип, так что новый слушатель добавляется в конце Object[] и для индекса i , Object[i] - это тип слушателя, а Object[i+1] - это экземпляр слушателя.

public synchronized <T extends EventListener> void add(Class<T> t, T l) {
    // There were other checking here
    // omitted as irrelevant to the discussion
    } else {
        // Otherwise copy the array and add the new listener
        int i = listenerList.length;
        Object[] tmp = new Object[i+2];
        System.arraycopy(listenerList, 0, tmp, 0, i);

        tmp[i] = t;  // add the class type
        tmp[i+1] = l;  // add the listener instance 

        listenerList = tmp;
    }
    }

ШАГ 3: Функция fireStateChanged() в JSlider отвечает за отправку события каждому слушателю списка. Исходный код говорит нам, что он вызывает функцию stateChanged() каждого слушателя, посещая их из конца списка слушателей.

protected void fireStateChanged() {
        Object[] listeners = listenerList.getListenerList();
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i]==ChangeListener.class) {
                if (changeEvent == null) {
                    changeEvent = new ChangeEvent(this);
                }
                ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
            }
        }
    } 

Summery: Механизм (синхронизированного) добавления и посещения слушателей в списке слушателей говорит нам, что: он поддерживает порядок LAST ADD FIRST VISIT. То есть сначала будет вызываться добавленный позднее (дочерний) прослушиватель, затем предыдущий (родительский) добавленный прослушиватель и так далее. Код обработки событий Swing работает на EDT. И когда EventQueue отправляет событие в том же порядке, что и enqueued, дочернее событие будет отправлено до родительского события.

Так что я верю, что приказ поддерживается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...