2010-01-29 6 views
8

В приложении Swing у меня есть несколько подпанелей, каждый из которых прослушивает один JSlider. Окружающая родительская панель также прослушивает все вспомогательные панели. Чтобы получить согласованные результаты в приведенном ниже примере, мне пришлось сначала добавить родителя и , а затем - локальный слушатель. Это имеет смысл, учитывая порядок, предписанный в EventListenerList и объясненный в этом article. Могу ли я полагаться на этот заказ или я должен организовать отправку другого мероприятия?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, более надежно обеспечивает правильный порядок. Например, SubPanelChangeListener может просто передать событие родительскому объекту.

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

Интересный вопрос и обсуждение! 1+ –

+0

Приложение ['Конвертер'] (http://docs.oracle.com/javase/tutorial/uiswing/components/panel.html) включает пример в' КонвертерRangeModel'. – trashgod

+0

Я только что получил ваше сообщение в то время как 'googling', хотел объяснить подробно. пожалуйста, сделайте почтовый подсчет и укажите мне, если что-то, что я описал, может быть неправильным! – Sage

ответ

4

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

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

+0

В общем случае события изменения состояния (в отличие от ввода) более надежны, чтобы полностью игнорировать объект события. (Не путайтесь с производительностью - подумайте о том, сколько циклов вы используете по сравнению с миллионами *, средний процессор может делать за миллисекунду). –

+0

@Tom: это комментарий к моему ответу или его вопрос? – pstanton

+0

ОК, ну, ваша точка зрения не совсем ясна. – pstanton

1

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

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

Я считаю, что они поддерживают порядок, документация компоненты не говорят нам много, но исходный код всегда наш друг. Начнем с 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: Механизм (синхронизированный) добавление и посещение слушателей в списке слушателей говорит нам, что: это сохранить ПОСЛЕДНИЙ добавить первый заказ VISIT. То есть более поздний (дочерний) добавленный слушатель будет вызываться первым, затем предыдущим (родительским) добавленным слушателем и так далее.Код обработки событий Swing работает на EDT. А так как EventQueue отправляет событие В том же порядке, что и enqueued, дочернее событие будет отправлено до родительского события.

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

+1

Хотя интересный шаблон дизайна, это деталь реализации, на которую я неохотно полагаюсь. – trashgod

+0

возможно, но для меня, вызвав механизм 'EventListListener' * ненадежный * кажется, мы его ругаем :);) – Sage

+1

просто для подчеркивания комментария @ trashgod: порядок уведомления явно не указан (см. F.i. spec beans). Кроме того, порядок может меняться в течение времени жизни наблюдаемого, f.i. путем удаления/добавления слушателей при изменении LAF. Таким образом, как правило ** не полагаются на какую-либо конкретную реализацию, это может измениться без предупреждения! – kleopatra

Смежные вопросы