EventListenerList触发顺序
在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); }
由于JSlider和JComponent等的文档没有提到监听器通知的顺序,我会毫不犹豫地依赖它,至少没有对JRE的每个后续版本进行全面测试。
如果你真的需要依赖命令,可以考虑设置一个监听器链,即监听器将通知监听器两个等。
有点老了,很晚才回答。 但我不稳定的头脑真的迫使我进入。
我可以依赖该订单,还是应该安排发送不同的活动?
我相信他们维护订单,组件的文档并没有告诉我们多少,但源代码始终是我们的朋友。 让我们从addChangeListener(listener)
函数开始:
步骤1:调用jSlider.addChangeListener(listener)
将listener
添加到listener list
。
public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); }
第2 EvenListenerList
: EvenListenerList
源代码: synchronized add(Class
:添加侦听器和相应的类型,以便在Object[]
的末尾添加新的侦听器,并添加索引i
, Object[i]
是侦听器的类型, Object[i+1]
是侦听器实例。
public synchronized void add(Class 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: JSlider
的fireStateChanged()
函数负责将事件发送到列表的每个侦听器。 源代码告诉我们它通过从侦听器列表的末尾访问它们来调用每个侦听器的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:在侦听器列表中(同步)添加和访问侦听器的机制告诉我们:它保持最后添加第一个访问顺序。 也就是说,后来(子)添加的侦听器将首先被调用,然后是前一个(父)添加的侦听器,依此类推。 Swing事件处理代码在EDT上运行。 并且当EventQueue
调度事件时,按照它们enqueued
顺序,将在父事件之前调度子事件。
所以我确实相信订单正在维持。