EventListenerList触发顺序

时间:2010-01-29 04:00:07

标签: java swing event-listener

在Swing应用程序中,我有许多子面板,每个子面板都会监听一个JSlider。周围的父面板也会监听所有子面板。为了在下面的示例中获得一致的结果,我必须首先添加父项,然后然后添加本地侦听器。考虑到EventListenerList中规定的顺序并在此article中进行了解释,这是有道理的。我可以依赖该订单,还是应该安排发送不同的活动?

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的{​​{1}}可以简单地将事件转发给父级。

ChangeListener

2 个答案:

答案 0 :(得分:4)

由于JSlider和JComponent等的文档没有提到监听器通知的顺序,我会毫不犹豫地依赖它,至少没有对JRE的每个后续版本进行全面测试。

如果你真的需要依赖订单,可以考虑设置一个监听器链,即监听器会通知监听器两个等。

答案 1 :(得分:1)

有点老而且很晚才回答。但我不稳定的头脑真的迫使我进入。

  

我可以依赖该订单,还是应该安排发送不同的订单   事件

我相信他们维护订单,组件的文档并没有告诉我们多少,但 源代码 始终是我们的朋友。让我们从addChangeListener(listener)的{​​{1}}函数开始:

第1步:致电JSliderjSlider.addChangeListener(listener)添加到listener

listener list

第2步源代码public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } EvenListenerList:添加侦听器和相应的类型,以便在synchronized add(Class<T> t, T l)的末尾添加新的侦听器对于索引Object[]i是侦听器的类型,Object[i]是侦听器实例。

Object[i+1]

第3步: 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; } } fireStateChanged()函数负责向列表中的每个侦听器发送事件。源代码告诉我们它通过从侦听器列表的末尾访问它们来调用每个侦听器的JSlider函数。

stateChanged()

Summery:在侦听器列表中添加和访问侦听器的(同步)机制告诉我们:它保持最后添加第一个访问顺序。也就是说,后来(子)添加的侦听器将首先被调用,然后是前一个(父)添加的侦听器,依此类推。 Swing事件处理代码在EDT上运行。当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); } } } 调度事件时,调度顺序与EventQueue相同,子事件将在父事件之前调度。

所以我确实认为订单正在维护。