Part III
Copyright © 2003 by Charlie Calvert
This is the third part of a
three part article
.
Go to Part I
Go to Part II
Key Listener Interface
Though it is not
shown in Listing 1, the KeyListener interface is also supported by
the MouseKey program. The KeyListener interface looks like this:
public interface KeyListener extends EventListener
{
public void keyTyped(KeyEvent e);
public void keyPressed(KeyEvent e);
public void keyReleased(KeyEvent e);
}
You won't see this interface in the MouseKey program exactly
as shown here. However, the InputPanel class implements each of these
methods in order to fulfill the contract implied by having a class that descends
from this interface. In other words, each of the methods of this interface
are implemented not in their own standalone class, but in the InputPanel class.
keyTyped events do not provide as much detailed
information about the key event as keyPressed events. They only tell you
what key was pressed, and do not tell you the key code. You will learn
more about key codes later in the chapter. The Sun documentation suggests
that you consider keyPressed events as the preferred way to get character
input since they are more completely platform independent. On the other
hand, if you want to know a bit more about which key was pressed on a
Windows or Linux platform, then use keyTyped.
Creating the KeyPanel and MousePanel
After setting up the InputPanel, you
should create two more JPanel descendants called KeyPanel and
MousePanel. Give them the appearance of the two top windows shown in
Figure 3. Because of space considerations, I don't want to explain
these classes in too much detail. If you need help building them,
just look at the code for MouseKey program found on my site and on sourceforge. But you
should be able to recreate their general appearance just by passing
your code on what you see in Figure 3.
These two panels will be used to
display the input that occurs in the InputPanel. In particular, when
the user clicks in the InputPanel, then a report of that mouse event
will be shown in the MousePanel. If the user types on the InputPanel,
then a report of the user's keypresses will be shown in the KeyPanel.
I will explain later in the chapter exactly how the code to display
the information should look. For now, just create the interface.
Registering a Listener
Let's take a
moment here to contemplate what has happened. You have stated that
your class, InputPanel, supports interfaces designed to handle mouse
input and keyboard input. Declaring all these interfaces gives you
the potential to receive events.
To switch from being a potential listener to being an
actual recipient of events, you need to register yourself with the class
that will generate the events. You will probably do this in the
jbInit method of the InputPanel:
this.addKeyListener(this);
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.addMouseWheelListener(this);
After adding
these methods, the only thing you have left to do is fill in the code
in the methods that receive the events. In this case, all we really
want to do is record that we are receiving the events. So you could
write something like this:
System.out.println("Mouse clicked pressed.");
However, we want to do something a
little bit more interesting. In particular, we want to show the
output in the KeyPanel and MousePanel classes that you created. In
the next section you will see how to proceed.
Using the KeyPanel and MousePanel
As you know, the mouse and keyboard input recorded by the
InputPanel is displayed on the interface for the KeyPanel and MousePanel
classes. In the InputPanels constructor, pass in the instances of the
mousePanel and keyPanel so that it will have access to them:
MousePanel mousePanel;
KeyPanel keyPanel;
public InputPanel(MousePanel mousePanel, KeyPanel keyPanel)
{
this.mousePanel = mousePanel;
this.keyPanel = keyPanel;
this.addKeyListener(this);
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.addMouseWheelListener(this);
}
Now the InputPanel will be able to send
messages to these panels when it receives input:
public void keyPressed(KeyEvent e)
{
keyPanel.keyTyped(e.getKeyChar(), e.getKeyCode());
Frame1.say("Method keyPressed() .");
}
public void mouseMoved(MouseEvent e)
{
mousePanel.setMouseX(e.getX());
mousePanel.setMouseY(e.getY());
}
The methods keyPanel.keyTyped and
mousePanel.setMouseX and mousePanel.setMouseY simply display the data
that is passed to them. Here is the keyTyped method from
KeyPanel.java:
public void keyTyped(char key, int code)
{
jTextField1.setText(new String() + key);
jTextField2.setText(new String () + code);
if (code == 8)
{
String s = jTextArea1.getText();
s = s.substring(0, s.length() -1);
jTextArea1.setText(s);
}
else
{
jTextArea1.append(new String() + key);
}
}
And here is the method setMouseX from MousePanel.java:
public void setMouseX(int mouseX)
{
this.mouseX = mouseX;
jTextField2.setText(String.valueOf(mouseX));
}
The JTextFields and JTextAreas
that display data in the MousePanel and KeyPanel get the data that
they will display from these calls to setMouseX, setMouseY and
keyTyped. Look at Figure 3 if you need clarification about what these
methods do.
You should also note how the methods of
the KeyEvent and MouseEvent classes are used to acquire specific
information about the state of the keyboard or the mouse. For
instance, the MouseEvent.getX() method tells the current X position
of the mouse. The KeyEvent.getKeyChar() method reveals the key that
the user pressed, such as the "A" or "B" key.
More detailed information, such as the ASCII code of the key, can be
found by calling getKeyCode. There are, of course, additional methods
on all of these objects that you can use.
Finally, you should add a method to the
InputPanel that sends more generic information to the MousePanel:
protected void say(String outString)
{
mousePanel.addString(outString);
}
Using the say method you can quickly
output a good deal of detailed information. For instance, these three
lines of code use the MouseWheelEvent class, declared here as the
variable e, to talk about the state of the wheel found in the middle
of most modern mice:
say("mouseWheelMoved, wheel rotation: " + e.getWheelRotation());
Frame1.say("mouseWheelMoved, scroll amount: " + e.getScrollAmount());
Frame1.say("mouseWheelMoved, unitsToScroll: " + e.getUnitsToScroll());
NOTE: The mouse wheel classes are part of JDK 1.4
The end result of all this passing
around of information is to produce the program called MouseKey that
is shown in Figure 3. When using the program, as long as you focus
the bottom window, then any mouse or keyboard input that you produce
will be shown in the two upper windows.
Virtual Desktops: JDesktop, JInternalFrame, and
MDI Programs
As you may have noticed, the MouseKey
program has an unusual interface. It accepts mouse and keyboard input
in one window, and allows you to see the mouse events in a second
window and the keyboard events in a third window, as shown in Figure
3. To do this, I used a JDesktopPane and JInternalFrame to
create a virtual desktop. In the Windows world, this is called an MDI
interface. MDI stands for Multiple Document Interface.
In Figure 3, you can see that three
windows are shown as children of the main window. In particular,
Frame1 owns three other windows called InputPanel, MousePanel
and KeyPanel. These windows are not dialogs that float on top of
Frame1, instead they are children of Frame1 that live
on its surface, much as a JButton or JTextField lives
on the surface of a JFrame. The big difference is that a
JButton stays in one place and never changes size, while these
windows are moveable and re-sizeable. You cannot, however, move them
outside the boundaries of Frame1.
To support the MDI interface you should
first declare a class called JDesktopPane:
JDesktopPane desktop;
Declare this class at the top of
Frame1, up where JBuilder places the declarations for
JButtons, JTextFields and other data members of the
class. In your jbInit method, you will declare that the
JDesktopPane instance you create will live on the surface of
Frame1:
desktop = new JDesktopPane();
contentPane.add(desktop);
The desktop will be the surface on which the MDI windows
will live.
You can actually place one of the
JPanel descendants we have created on the desktop by using the
following code:
private
void createFrame(int x, int y, JPanel panel, int width, String caption)
{
JInternalFrame j = new JInternalFrame(caption,
true, // Window is resizable
true, // Window has a close icon
true, // Window has a maximizable icon
true); // Window can be minimized to an icon
j.setBounds(x, y, width, 250);
j.setContentPane(panel);
desktop.add(j);
j.show();
}
A JInternalFrame is a
lightweight container for the windows that will be residing on the
JDesktopPane instance. The first parameter in the
JInternalFrame constructor is the name you want to give the
window. This name will appear in the Windows caption bar. The next
four parameters are Boolean values. Use them to decide whether the
window can be resized, closed, maximized or minimized and shown as an
icon.
The code then goes on to set the bounds
of the window. The next step is to place the JPanel instance
that we are working with inside the JInternalFrame and then
add it to the JDesktopPane instance:
j.setContentPane(panel);
desktop.add(j);
In your jbInit, add the
following code, which calls the createFrame method that we have just
finished exploring:
desktop = new JDesktopPane();
contentPane.add(desktop);
createFrame(10, 10, mousePanel, 250, "Mouse Panel");
createFrame(500, 10, keyPanel, 250, "Key Panel");
inputPanel = new InputPanel(mousePanel, keyPanel, "Input Panel);
createFrame(150, 275, inputPanel, 400);
Mouse Adapters
Before closing this chapter, I want to cover one last easy
to understand topic which has fairly significant ramifications for event
programmers. The MouseAdapter class, discussed in this section, provides
you with some important and frequently used shortcuts to development of
event handling code.
An interface like MouseListener can be
a bit intimidating at times. If all you want to do is find out when
the mouse was clicked, it seems like quite a bit of trouble to have
to implement five methods. (Of course the Interface Wizard makes your
task simpler, but still there is the sheer bulk of all those
methods strewn through your code like so much confetti.)
Sun provides a possible solution to this problem by
supplying developers with a JDK class called
java.awt.event.MouseAdapter:
public abstract class MouseAdapter implements MouseListener
{
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
This class provides a very minimal implementation of the
MouseListener interface. All of the methods are entirely empty, but they
do in fact exist as a pair of curly braces: {}. Given this class you can
implement your mouseClicked event very simply:
class MyClass extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
// Do your stuff here.
}
}
It should be fairly obvious that it is simpler to extend the
MouseAdapter class rather than implement the MouseListener interface. Of course,
the actual path you want to follow will differ on a case by case basis.
Summary
In this chapter you learned several
different ways that a class can receive events. The chapter started
out with a simple explanation of using the inspector to pick up on
the most common events, such as a click on a button. You learned that
there are several different ways to handle these events, including
the use of anonymous and standard adaptors.
The text then went on to explore event
listener interfaces, which can be used to enable a class to receive
various events that are not listed in the JBuilder inspector. This
section of the text focused on learning about MouseListeners,
MouseMotionListeners, MouseWheelListeners, and KeyListeners.
As an aside, you also learned how to
use JDesktopPane and JInternalFrame to produce MDI
applications, or virtual desktops. This proved to be a very easy
subject to understand.
In the next chapter, you are going to
turn the whole subject on its head, and learn how a class can fire
events. In that chapter you will also learn how to create custom
events.
Connect with Us