Event Handling in JBuilder Part III, by Charlie Calvert

By: Charlie Calvert

Abstract: This is the third part of a three part article on Event Handling in JBuilder. The text is an excerpt from my book, Charlie Calvert's Learn JBuilder, from WordWare publishing.

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.


Server Response from: ETNASC02