Java 211 – Lecture X Events and Listeners Yosef Mendelsohn Events At this point in your programming, you have learned how to get input from the user from the keyboard. For example, you may want to read in a string of text, or an integer value, or some other type of textual data. However, input to your program can come in many forms. For example, many situations in computers receive input from other sources such as the mouse. Clicking on the left-mouse button is one of many possible “events” in which your program may be interested. For example, you have all seen dialog boxes in which you have to click on ‘OK’ or ‘CANCEL’. These dialog boxes typically require input from the mouse to which the program will then respond accordingly. In Java, events can be generated all kinds of ways: - clicking on a mouse button - pressing the up-arrow key on your keyboard - clicking on the ‘OK’ button in a dialog box - clicking on the down-arrow button at the bottom of a slider The Java standard class library contains many classes that represent events in which the programmer may be interested. Methods in the MouseListener interface Following is a list of events that can be generated by a mouse. All of these events are present as (abstract) methods inside an interface called ‘MouseListener’. - mousePressed - mouseReleased - mouseClicked - mouseEntered - mouseExited For example, in a properly implemented program, a single-click on the left mouse button will cause the methods mousePressed(), mouseReleased(), and mouseClicked() to be executed. You can get a program to respond to one or more of these methods by creating a class that implements the MouseListener interface. Naturally, implementing the MouseListener interface means that we must implement all of the above methods. However, we do not have to give all of the methods valid bodies; some of them may be empty methods. Depending on the situation, we will implement one or more of the methods with code to respond appropriately. MouseMotionListener interface Two other events you may want to have your program respond to are: mouseMoved, and mouseDragged. These abstract methods are in the MouseMotionListener inteface. These events (methods) are continually called as the mouse is moved and/or dragged. Listeners By implementing some of the various methods discussed above, you are writing code that will get executed when some event in your program takes place For example, if the user clicks on a certain button in an applet, the mousePressed, mouseReleased, and mouseClicked events in the appropriate class will be invoked. However, a question remains: How does the program know which class to invoke? For example, you may have fifteen different classes all of which implement the MouseListener interface differently. Which class’ methods should be invoked in response to clicking on the button in your applet? The answer, is to make a “connection” between the object you want “responded” to (e.g. the button in your applet) and another object called a listener. When an event occurs, the button (i.e. the listener object) that generated the event will notify the listener object. The listener object will then automagically invoke all the appropriate methods of that listener. The Java standard class library contains a number of listener interfaces. Each interface is a collection of methods grouped by category. For example, the MouseListener interface or the MouseMotionListener interface. Another commonly used interface is the KeyListener which listens and responds to key press events on the keyboard. MouseEvent class When an event occurs (e.g. the mouse button is released), the appropriate event (method) is automatically called. In this, case, the mouseReleased method. Examination of the signature of the mouseReleased method shows that the method takes one parameter of type MouseEvent. When the mouseReleased method is called, the program automatically passes along a parameter of type MouseEvent. This MouseEvent object contains (encapsulates) all kinds of information about the event that occurred. For example, the MouseEvent object contains, among other information, the x and y coordinates of the location on the screen where the mouse was clicked. Some methods of the MouseEvent class include: - getX (returns an int) - getY (returns an int) - getPoint (returns a Point object) Connecting the event generator to a listener class All components that can generate events such as buttons, drop-down menu boxes, or applets, have methods we can invoke that will “connect” the item that generates the event (e.g. an applet) with the appropriate listener class that is supposed to respond to it. For example, since applets are sometimes meant to respond to mouse clicks (just like buttons are), the applet class has a method called ‘addMouseListener()’ that allows you to add a MouseListener object to the applet. FYI: The addMouseListener() method is defined in class ‘Component’, not in class ‘Applet’. This makes sense since you may want to invoke this method for many different types of objects, not just applets. That is, every object that is a component object, can invoke the addMouseListener() method. Question: Are applets components? Generating the event Note: Even though it is the mouse that actually does the clicking, the event is actually considered as having been generated by the object that was clicked on. So in the above example, the applet is said to have “generated the event”. See MouseClickApplet.java To summarize: 1. Begin with an object that can generate an event (e.g. an applet or a button) 2. Decide which kinds of events you would like your object to generate (e.g. mouse clicks, keyboard presses, etc.) 3. Create a listener class for the event (or events) that you want responded to. For example, if you wish an applet to generate events when the mouse is clicked, you would need to create a MouseListener or MouseMotionListener class. You can create such a class by implementing the MouseListener (or MouseMotionListener) interface. 4. “Add” the listener to the class that generates the events. For example, in the case of an applet, you would call the method ‘addMouseListener’ from inside the applet. The addMouseListener method connects the event-generating class (the applet) with the listener class. The addMouseListener method takes one argument of type MouseListener. So you must have at least one class around that has implemented the MouseListener interface. You can then instantiate that class and pass it as an argument to the addMouseListener interface. See Dots.java and DotsMouseListener.java Don’t Forget: When a listener class is notified that an event has occurred, the listener class calls all of the appropriate methods based on the event that occurred (e.g. mousePressed). Each method of the listener takes one argument. The argument contains all kinds of information about the event that took place. For example, if a key on the keyboard was pressed, the event object encapsulates information about what key was pressed. If a mouseListener class is involved, the event encapsulates information such as the x and y coordinates of the location where the mouse was clicked. Making the event-generator a listener To make any class a listener class is easy. You simply put the ‘implements’ clause after the class header, and then implement all of the methods in that interface. That is, any class that implements one of the interface listeners is automatically a listener class. For example, to make an applet called DumbApplet a MouseListener, we could do the following: class DumbApplet extends Applet implements MouseListener { Notice how DumbApplet is now both an applet and a MouseListener. Now you don’t have to worry about creating a separate class as a listener. You need only implement the methods from the MouseListener class inside the applet, and you are home free. This saves you from having to create another class, import it, and instantiate it inside the applet. Instead, you can “add” the listener class to your applet (step 4 above) by using the following line: addMouseListener(this); //the calling object (i.e. the applet) // also serves as a mouseListener object This calls the addMouseListener method of the Applet class (or, more accurately, of the Container class). Don’t forget that addMouseListener requires a MouseListener object as its argument. However, since the applet is also a MouseListener, you can pass ‘this’ as the argument and, voila, you have connected your event-generator to a listener. Now take a look at RubberLines.java. Notice how in this program (just like the MouseClickApplet we examined earlier), the applet itself is implemented as a listener. Again, this saves us from some of the complications of the Dots programs since we don’t have to create separate classes, instantiate them, etc. It must be noted that while having the event-generator do double-duty as a listener is convenient, it is also in conflict with the idea of modularity. Typically, we should design our classes to carry out only the objectives necessary to the proper use and functionality of that class. Implementing a complicated interface within an applet is not always a good idea. It is always better to distribute responsabilities among various classes. There is one compromise: If a listener is designed to work only with one specific component (e.g. a specific applet), you can write a separate listener class, but make it a nested class. See Direction.java. In this case, you are accomplishing the objective of properly delegating tasks to specific classes, while at the same time, reducing the complexities involved in communication between the event-generator and the listener class. In Direction.java we see some new things: - using Images - using the KeyListener interface (look up in API) - using sounds (look up AudioClip in the API) - nested classes At this point, take another look at the Dots programs discussed earlier. Notice the extra work involved in separating the classes out: - two separate classes in separate files - the listener class must be instantiated in the applet - a reference to the applet must be maintained inside the listener class private Dots applet; As your programs become more involved, you will have to follow this method, but for simpler applications, you can use nested classes.