Swing: Use Event-Specific Utilities

Often times when developing in Swing, you need to implement your own events and listener API. A naive approach would be to simply use a basic collection:

 

public class SomeClass {
 private List listeners = new ArrayList();
 public void addSomeClassListener(SomeClassListener l) {
  listeners.add(l);
 }
 
 public void removeSomeClassListener(SomeClassListener l) {
  listeners.remove(l);
 }
 
 protected void fireEvent() {
  SomeClassEvent evt = new SomeClassEvent();
  for(Iterator iter = listeners.iterator(); iter.hasNext(); ) {
   SomeClassListener aListener = (SomeClassListener)iter.next();
   aListener.eventHasOccurred(evt);
  }
}

 

The biggest problem with this example is that it is simply not thread-safe. The listeners list can easily be changed by thread A at the same time that thread B is iterating the collection.

There is a set of three classes that have been around for a long long time in Java that are designed to solve the worst of these problems, and it's typically good practice to use them as opposed to a one-off home baked solution:

 

  • javax.swing.event.EventListenerList - A thread-safe 'collection' for implementations of the EventListener interface.
  • java.util.EventListener - A marker interface for a listener for some event.
  • java.util.EventObject - A helpful super class for the event object that includes a 'source' object reference.

 

Using these classes is fairly straight-forward:

 

public class SomeClassEvent extends EventObject {
 public SomeClassEvent(SomeClass source) {
  super(source);
 }
 // ...
}
 
public class SomeClassListener implements EventListener {
 void eventHasOccurred(SomeClassEvent evt);
}
 
public class SomeClass {
 private EventListenerList listeners = new EventListenerList();
 public void addSomeClassListener(SomeClassListener l) {
  listeners.add(SomeClassListener.class, l);
 }
 
 public void removeSomeClassListener(SomeClassListener l) {
  listeners.remove(SomeClassListener.class, l);
 }
 
 public void fireEvent() {
  SomeClassEvent evt = new SomeClassEvent(this);
  // Java 5 inferred type
  SomeClassListener[] listenerArry = listeners.getListeners(SomeClassListener.class);
  for(int i=0; i<listenerArry.length; i++) {
   SomeClassListener listener = listenerArry[i];
   listener.eventHasOccurred(evt);
  }
 }
}

 

Now your code has some standard listener pattern in place, and your listener list is thread-safe. Note the use of the 'SomeClassListener.class' reference through-out the code. This is because the event listener list can contain events of varying types - when you call getListeners(Class<T>) it filters the internal collection down to just listeners of that type. Note that while I think it is good enough to get the job done, I personally feel there are some implementation short-comings with the EventListenerList API - what do you think - do you have a better approach?

Until next time,

R.J. Lorimer
Contributing Editor - rj -at- javalobby.org
Author              - http://www.coffee-bytes.com
Software Consultant - http://www.crosslogic.com

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值