KeyInterpreter and MouseInterpreter

The KeyInterpreter and MouseInterpreter classes allow any object to receive the same simple key and mouse event notifications that WindowController gets. You simply create an interpreter as you would any other object, giving it as a target an object that has some or all of the required methods.

Table of Contents

1. Creating a MouseInterpreter

A WindowController subclass automatically creates itself a MouseInterpreter, which is what allows it to be notified of mouse events through the methods onMouseDrag() and the like. If you would like another object to be able to receive mouse events in the same way, you can create another MouseInterpreter for your class, using this constructor:

public MouseInterpreter(Object target, DrawingCanvas canvas)

The target can be any object at all, although, as discussed below, it ought to implement certain methods to be notified of events. You can create as many MouseInterpreters on a canvas as you wish; they will all trigger when a mouse event occurs.

At some point you may want to stop receiving mouse event notification. For example, the object receiving the mouse events may be an ActiveObject, and you may want to have it stop getting events when it finishes running. You can remove it from the canvas like any other object:

public void removeFromCanvas()

MouseListener also has the other methods for dealing with the canvas. So, for example, if you want to stop listening to mouse events for a while, but then start up again, you can add it back to the canvas:

public void addToCanvas(DrawingCanvas canvas)
public DrawingCanvas getCanvas()

2. Receiving events from a MouseInterpreter

In order to be notified of mouse events, your class, whether it is a WindowController or another MouseInterpreter target, must contain methods that look exactly like this:

public void onMousePress(Location point)
public void onMouseRelease(Location point)
public void onMouseMove(Location point)
public void onMouseClick(Location point)
public void onMouseDrag(Location point)
public void onMouseEnter(Location point)
public void onMouseExit(Location point)

You need not implement all of these methods; you can implement only the ones you are interested in dealing with.

Mouse dragging and releasing events are sent only if the mouse was pressed inside the window. So, if the user clicks outside the window, drags into the window, and releases, you receive just a onMouseEnter() event, until the mouse is released, at which point you start to receive onMouseMove() events. Similarly, if the mouse is pressed inside the window, you will continue to receive onMouseDrag() events, and will receive an onMouseRelease() event, even if the mouse moves outside the window and is released there. This guarenteed sequence of press, drag, release, that always occurs with all three parts or none at all, means that you can safely drag an object by doing something to pick it up in the onMousePress() method, moving it in the onMouseDrag() method, and doing whatever you need to do to release it in the onMouseRelease() method.

The method onMouseClick() will only be called if the mouse is clicked - pressed and released - quickly, and without moving in between. The exact settings for what constitutes a click depend on your computer. So, if you don't care much about how exactly the user clicked, it is often easier to just use the onMousePress() method.

The Location given as a parameter to these methods describes where on the screen the user clicked. A typical use for it would be to create an object there or test if it is inside another object.

3. A typical class that uses a MouseInterpreter

Your browser doesn't do Java.
TargetPractice.java
ActiveTarget.java
Here is a simple example of using a MouseInterpreter: this ActiveObject creates an oval that moves in a circle, counting how many times it is clicked on, and disappears when it has been clicked ten times. Notice that ActiveTarget creates a MouseInterpreter to feed me events, passing itself as the target, by doing new MouseInterpreter(this, canvas). Also notice that because we only care about mouse press events, I write only the onMousePress() method.

4. Creating a KeyInterpreter

As with MouseInterpreter, there is a KeyInterpreter automatically created for a WindowController, but if you want any other class of object to receive mouse events in the same way, you need to create a KeyInterpreter for it:

public KeyInterpreter(Object this, DrawingCanvas canvas)

As with MouseInterpreter, you can create as many KeyInterpreters as you want, and they will all be notified of key events. Also, you can remove the KeyInterpreter from its canvas to have it stop receiving events, add it back to have it start again, and so on, as with MouseListener.

public void removeFromCanvas()
public void addToCanvas(DrawingCanvas canvas)
public DrawingCanvas getCanvas()

5. Methods to receive specific key events

The methods that are called when a key is pressed depend on the name of the key you want to pay attention to. So, for example, if I wanted to be notified when the space bar is pressed and later when it is released, I would implement these two methods:

public void onSpacePress()
public void onSpaceRelease()

Here, Space could be replaced with the name of any key you want to receive notifications about. Most of the letter and number keys have names that are simply what the key types; onAPress(), for example. If you want to figure out what name objectdraw uses for a particular key, look at the full list of Key Code Names.

6. An example of using a KeyInterpreter

Your browser doesn't do Java.
KeyControl.java
ControlledObject.java
Because you only receive one event to notify you that a key was pressed and then another when it is released, with nothing in between, it doesn't work well to move an object directly when the key is pressed. This would require the user to press the key every time that they wanted the objet to move. More often, what I do is to set an instance variable to remember that the key is down, and have the active loop in my run() method notice the state of that variable and move the object accordingly.

7. Receiving all other key events

Sometimes, you want to be able to receive key events all in one place, rather than having a separate method for every key. Or, you may want to be able to respond specifically to a key when it is accompanied by a certain combination of modifiers - the keys shift, control, and so on. If an event is not passed along to a specific method for its particular key, it will instead be passed along to the method onOtherPress() or onOtherRelease():

public void onOtherPress(String key)
public void onOtherRelease(String key)

The "key" here is the same name that would appear in the method name ("space" or "a" or whatever), but with a few changes:So, if I were to press space with all the modifiers down (shift, control, meta, alt), the key passed to onOtherPress() would be "&^~space". If I get "^~space" as the key, the control and option keys are down, but space is not. The modifiers are always listed in this particular order.
Your browser doesn't do Java.
TypeInOval.java

The applet to the right uses onOtherRelease() to detect the "^i" and "^b" key strokes for changing the bold and italic style of text. It also detects the delete and backspace keys this way. I could have written an onBack_spaceRelease() method to handle that key individually, but the nice thing about using onOtherRelease() is that I know that no modifier was being held down when it was typed. The user might expect some strange result from pressing ctrl-backspace.

There is one last method you might want to make available for KeyInterpreter to call. Suppose that a key press resulted in some text being typed. For example, when the user hits the 8 key, "8" is typed, but if they are holding down shift as they do it, "*" is typed. Knowing what text was typed would allow you, for example, to let someone type their name in to appear on the screen.

public void onKeyTyped(String typed)

This method is called only when a key event results in actual text being typed. Many key events (like ctrl-i) don't actually type anything. The applet to the right uses this method to insert text in the oval when you type.

8. Key names

Your browser doesn't do Java.
KeyLister.java
The key names used in method names such as onSpacePress(), and as a parameter to onOtherPress() and its counterparts, are the "virtual key" names listed as constants in the KeyEvent class:

Official KeyEvent javadocs

To find out the name for a key, click in the applet to the right, then press an hold a key. The applet displays a list of all keys that are held down. Here is a nearly complete list of the possible keys:

9. Complete specification of KeyInterpreter and MouseInterpreter

Constructing a KeyInterpreter or MouseInterpreter:

public KeyInterpreter(Object target, DrawingCanvas canvas)
public MouseInterpreter(Object target, DrawingCanvas canvas)

Adding to or removing from canvas:

public void removeFromCanvas()
public void addToCanvas(DrawingCanvas canvas)
public DrawingCanvas getCanvas()

Methods of target that will be called by MouseInterpreter:

public void onMousePress(Location point)
public void onMouseRelease(Location point)
public void onMouseMove(Location point)
public void onMouseClick(Location point)
public void onMouseDrag(Location point)
public void onMouseEnter(Location point)
public void onMouseExit(Location point)

Methods of target that will be called by KeyInterpreter:

public void onSpacePress()
public void onSpaceRelease()
public void onAPress()
public void onARelease()
public void onBack_spacePress()
public void onBack_spaceRelease()
public void onNumpad1Press()
public void onNumpad1Release()
...

public void onOtherPress(String key)
public void onOtherRelease(String key)

public void onKeyTyped(String typed)