30.13. Review Questions

 
[Page 906 ( continued )]

27.6. (Optional) Creating Custom Event Sets

The Java API provides many event sets. You used the event set ActionEvent / ActionListener in the preceding section. A course object fires an ActionEvent when the enrollment cap is exceeded. It is convenient to use the existing event sets in the Java API, but they are not always adequate. Sometimes you need to declare custom event classes in order to obtain information not available in the existing API event classes. For example, suppose you want to know the enrollment cap and the number of students in the course; an ActionEvent object does not provide such information. You have to declare your own event class and event listener interface.


[Page 907]

A custom event class must extend java.util.EventObject or a subclass of java.util.EventObject . Additionally, it may provide constructors to create events, data members , and methods to describe events.

A custom event listener interface must extend java.util.EventListener or a subinterface of java.util.EventListener , and define the signature of the handlers for the event. By convention, the listener interface should be named <Event> Listener for the corresponding event class named <Event> . For example, ActionListener is the listener interface for ActionEvent .

Let us declare EnrollmentEvent as the event class for describing the enrollment event and its corresponding listener interface EnrollmentListener for defining a handler, as shown in Figure 27.7.

Figure 27.7. EnrollmentEvent and EnrollmentListener comprise an event set for enrollment event.

The source code for the enrollment event set is given in Listings 27.4 and 27.5.


[Page 908]
Listing 27.4. EnrollmentEvent.java
 1   public class   EnrollmentEvent    extends   java.util.EventObject  { 2   private int   numberOfStudents; 3   private int   enrollmentCap; 4 5  /** Construct an EnrollmentEvent */  6   public   EnrollmentEvent(Object source,   int   numberOfStudents, 7   int   enrollmentCap) { 8    super   (source);  9   this   .numberOfStudents = numberOfStudents; 10   this   .enrollmentCap = enrollmentCap; 11 } 12 13   public long   getNumberOfStudents() { 14   return   numberOfStudents; 15 } 16 17   public long   getEnrollmentCap() { 18   return   enrollmentCap; 19 } 20 } 

Listing 27.5. EnrollmentListener.java
 1   public interface   EnrollmentListener    extends   java.util.EventListener  { 2  /** Handle an EnrollmentEvent, to be implemented by a listener */  3    public void   enrollmentExceeded(EnrollmentEvent e);  4 } 

An event class is an extension of EventObject . To construct an event, the constructor of EventObject must be invoked by passing a source object as the argument. In the constructor for EnrollmentEvent , super(source) (line 8) invokes the superclass's constructor with the source object as the argument. EnrollmentEvent contains the information pertaining to the event, such as the number of students and the enrollment cap.

EnrollmentListener simply extends EventListener and defines the enrollmentExceeded method for handling enrollment events.

Note

An event class does not have a no-arg constructor, because you must always specify a source for the event when creating an event.


Let us revise CourseWithActionEvent in Listing 27.2 to use EnrollmentEvent / EnrollmentListener instead of ActionEvent / ActionListener . The new class named CouseWithEnrollmentEvent in Listing 27.6 is very similar to CourseWithActionEvent in Listing 27.2.

Listing 27.6. CourseWithEnrollmentEvent.java
(This item is displayed on pages 908 - 910 in the print version)
 1   import   java.util.*; 2 3   public class   CourseWithEnrollmentEvent { 4   private   String name =   "default name"   ; 5   private   ArrayList<String> students =   new   ArrayList<String>(); 6   private int   enrollmentCap =   10   ; 7 8   private   ArrayList  <EnrollmentListener>  enrollmentListenerList; 9 

[Page 909]
 10   public   CourseWithEnrollmentEvent() { 11 } 12 13   public   CourseWithEnrollmentEvent(String name) { 14   this   .name = name; 15 } 16 17   public void   addStudent(String student) { 18 students.add(student); 19 20   if   (students. size () > enrollmentCap) { 21  // Fire EnrollmentEvent  22  processEvent(   new   EnrollmentEvent(   this   ,  23  getNumberOfStudents(), getEnrollmentCap()));  24 } 25 } 26 27   public   String[] getStudents() { 28   return   (String[])students.toArray(); 29 } 30 31   public int   getNumberOfStudents() { 32   return   students.size(); 33 } 34 35   public int   getEnrollmentCap() { 36   return   enrollmentCap; 37 } 38 39   public void   setEnrollmentCap(   int   enrollmentCap) { 40   this   .enrollmentCap = enrollmentCap; 41 } 42 43  /** Register an action event listener */  44   public synchronized void    addEnrollmentListener  45  (EnrollmentListener listener)  { 46   if   (enrollmentListenerList ==   null   ) { 47 enrollmentListenerList =   new   ArrayList<EnrollmentListener>(   2   ); 48 } 49 50   if   (!enrollmentListenerList.contains(listener)) { 51 enrollmentListenerList.add(listener); 52 } 53 } 54 55  /** Remove an action event listener */  56   public synchronized void    removeEnrollmentListener  57 (  EnrollmentListener listener)  { 58   if   (enrollmentListenerList != 59   null   && enrollmentListenerList.contains(listener)) { 60 enrollmentListenerList.remove(listener); 61 } 62 } 63 64  /** Fire EnrollmentEvent */  65   private void    processEvent(EnrollmentEvent e)  { 66 ArrayList list; 67 

[Page 910]
 68   synchronized   (   this   ) { 69   if   (enrollmentListenerList ==   null   )   return   ; 70 list = (ArrayList)enrollmentListenerList.clone(); 71 } 72 73   for   (   int   i =     ; i < list.size(); i++) { 74 EnrollmentListener listener = (EnrollmentListener)list.get(i); 75  listener.enrollmentExceeded(e);  76 } 77 } 78 } 

Line 8 creates a java.util.ArrayList instance enrollmentListenerList for holding all the listeners for the source component. The data type of the elements in the array list is EnrollmentListener . The registration and deregistration methods for EnrollmentListener are declared in lines 44, 56.

The addStudent method adds a new student to the course and checks whether the number of students is more than the enrollment cap. If so, it creates an EnrollmentEvent and invokes the processEvent method to process the event (lines 22 “23). To create an EnrollmentEvent , use the constructor

 EnrollmentEvent(Object source,   int   numberOfStudents,   int   enrollmentCap) 

where source specifies the source component.

The processEvent method (lines 65 “77) is invoked when an EnrollmentEvent is generated. This notifies the listeners in enrollmentListenerList by calling each listener's enrollmentExceeded method to process the event.

Let us revise the test program in Listing 27.3 to use EnrollmentEvent / EnrollmentListener instead of ActionEvent / ActionListener . The new program, given in Listing 27.7, creates a course using CourseWithEnrollmentEvent (line 3), sets the enrollment cap to 2 (line 6), creates an enrollment listener (line 7), registers it (line 8), and adds three students to the course (lines 9 “11). When line 11 is executed, the addStudent method adds student Tim to the course and fires an EnrollmentEvent because the course exceeds the enrollment cap. The course object invokes the listener's enrollmentExceeded method to process the event and displays the number of students in the course and the enrollment cap.

Listing 27.7. TestCourseWithEnrollmentEvent.java
(This item is displayed on pages 910 - 911 in the print version)
 1   public class   TestCourseWithEnrollmentEvent { 2 CourseWithEnrollmentEvent course = 3   new   CourseWithEnrollmentEvent(   "Java Programming"   ); 4 5   public   TestCourseWithEnrollmentEvent() { 6  course.setEnrollmentCap(   2   );  7  EnrollmentListener listener =   new   NewListener();  8 course.addEnrollmentListener(listener); 9 course.addStudent(   "John"   ); 10 course.addStudent(   "Jim"   ); 11 course.addStudent(   "Tim"   ); 12 } 13 14   public static void   main(String[] args) { 15   new   TestCourseWithEnrollmentEvent(); 16 } 17 

[Page 911]
 18    private class   NewListener   implements   EnrollmentListener {  19   public void   enrollmentExceeded(EnrollmentEvent e) { 20 System.out.println(e.getNumberOfStudents() +   " enrolled"   + 21   " and the enrollment cap is "   + e.getEnrollmentCap()); 22 } 23 } 24 } 

The flow of event processing from the source to the listener is shown in Figure 27.8.

Figure 27.8. The listener is registered with the source course , and the source invokes the listener's handler enrollmentExceeded to process the event.

Tip

Using the ActionEvent / ActionListener event set is sufficient in most cases. Normally, the information about the event can be obtained from the source. For example, the number of students in the course and the enrollment can all be obtained from a course object. The source can be obtained by invoking e.getSource() for any event e .


Note

The EnrollmentEvent component is created from scratch. If you build a new component that extends a component capable of generating events, the new component inherits the ability to generate the same type of events. For example, since JButton is a subclass of java.awt.Component that can fire MouseEvent , JButton can also detect and generate mouse events. You don't need to write the code to generate these events and register listeners for them, since the code is already given in the superclass. However, you still need to write the code to make your component capable of firing events not supported in the superclass.


 


Introduction to Java Programming-Comprehensive Version
Introduction to Java Programming-Comprehensive Version (6th Edition)
ISBN: B000ONFLUM
EAN: N/A
Year: 2004
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net