Reputation: 22104
I often implement some panels, which provide common functionality like controls. For this I want to be able to add listeners, so that the caller can attach to the control and get notifications about changes.
So far I have simply used my own List
where I keep the listeners and when I want to fire an action I loop through the list and call the listeners. From the outside this basically looks like any other Swing
controls, however I was wondering if this is really the approach which should be used.
Especcially I was wondering if calling the listeners in a loop is what Swing
itself also does, or if there is some kind of queue where you would put the actions, so that Swing
decides when to deliver such actions.
When I investiaged this I came across this code:
protected void fireActionPerformed(ActionEvent event)
{
Object[] listeners = listenerList.getListenerList();
ActionEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2)
{
if(listeners[i] instanceof ActionListener)
{
// Lazily create the event:
if (e == null)
{
String actionCommand = event.getActionCommand();
e = new ActionEvent(this,
ActionEvent.ACTION_PERFORMED,
actionCommand,
event.getWhen(),
event.getModifiers());
e.setSource(event.getSource());
}
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
The member listenerList
from JComponent
is directly accessed, whcih feels a bit strange. However I didn't really find a better way so far. Also when adding a new listener to this, I do it now like shown below, but I'm not sure if this is really the appropriate way:
public void addQueryListener(ActionListener oListener)
{
listenerList.add(ActionListener.class, oListener);
}
public void removeQueryListener(ActionListener oListener)
{
listenerList.remove(ActionListener.class, oListener);
}
So I would like to know, is accessing the listenerList
member the correct way to add and remove listeners, so that they behave like any other standard control? Or is there some best practice
how this should be done, which I'm missing so far?
Upvotes: 2
Views: 750
Reputation: 7126
There's a good example in the EventListenerList
docs, and this Converter
example uses its own listenerList
in ConverterRangeModel
.
Upvotes: 1
Reputation: 2444
Keeping mind the restriction Swings put for Creating the gui. There is no harm accessing the ** listenerlist ** this way. May be this is not best approach. Swing is Suppose to be Single Threaded and is not Thread Safe.
http://codeidol.com/java/java-concurrency/GUI-Applications/Why-are-GUIs-Single-threaded/
AddListener and RemoveListener needed to be called on EDT(Event Dispatch Thread) see See http://en.wikipedia.org/wiki/Event_dispatching_thread.
Also See for iteration of Listenere i.e when you call getActionListeners
its creates a copy of ListenersList and returns you back
Below Code from EventListenerList
public <T extends EventListener> T[] getListeners(Class<T> t) {
Object[] lList = listenerList;
int n = getListenerCount(lList, t);
T[] result = (T[])Array.newInstance(t, n);
int j = 0;
for (int i = lList.length-2; i>=0; i-=2) {
if (lList[i] == t) {
result[j++] = (T)lList[i+1];
}
}
return result;
}
Upvotes: 1