HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

John Hillenbrand ([email protected]) writes:

How can I make an AWT form in Java that responds correctly to the TAB key to move the focus from field to field?

One of the nice features of many GUI platforms today is the use of the TAB key to hop from field to field. It is one feature that Java is lacking. But with a little finesse, you can make Java jump at your command.

If you look in the Java source code you will find that there is some low-level support for this behavior. However, it does not work in the Windows 95/NT version of the Java Virtual Machine (JVM).

Below is a code snippet from the TextField.java source code file:

/* Can this field be tabbed to? */
boolean tabbable() {
return true;
}

This code is used to determine if the component can be tabbed to. This is also in many of the other Java components.

In the Window class, there is a private class called FocusManager. It is responsible for, obviously, managing the focus. It asks each component if it can be tabbed to by using the tabbable() method. However, as stated above, this code is non-functional on the Windows 95/NT platform.

So, how can you get the TAB key to work the way you want? Easy! Create your own Panel class that manages the focus.

First, derive a new class from the Java Panel class. This will be your container that will manage the focus:

import java.awt.Panel;

public class
MyPanel
extends Panel

We need one variable in our class to keep track of our current position in the tab order. We'll call this currentPos:

protected int currentPos = 0;

We start it at zero because that is our first component.

Next, we need to grab the TAB key presses and move the focus. We do this in the handleEvent() method of our new class (see Listing 1).

We wait for an Event.KEY_PRESS for the TAB key. Once pressed, we see if the target of the event was a Java component. If it is, then we know we can tab off this to the next component. This is done with the focusForward() and focusBackward() methods.

A nice trick here is that we can easily support the back tabbing, or shift-TAB, by calling the event's modifier method shiftDown(). This returns true if the shift key was pressed in addition to the <tab> key.

Lastly, we want to eat the <tab> keystroke. We do this by returning true from handleEvent(). If the we don't handle the event, we send it up the inheritance hierarchy for processing.

Now we have a container that can handle tabbing. How do we make the cursor jump? That is done in the focusForward() and focusBackward(). Listing 2 looks at the code for the focusForward() method:

This method is relatively straightforward. It calls findNextComponent() to retrieve the next available component. The number returned is an index value into the components array of the Panel container. Each container keeps an array of components that it contains. This index allows you to jump around as you can see in Listing 2. After we retrieve the next component's number, we simply request the focus. Finally, as a bonus, we select the text if the component is a text component.

Moving the focus backward is just the opposite of moving it forward. Instead of finding the next component, we traverse the component array backwards looking for a component that we can tab to. But what defines a tabbable component? Simple, any component that is capable of input. That is any enabled, non-label component. Listing 3 is the code for the findNextComponent() method.

This method is called with one argument, and that is the position to start from. We increment this starting number and enter a loop. We don't return until we find a suitable component, or we've come full circle.

The countComponents(), a method from our base class Panel, returns the number of components contained in our Panel. By using this value, we can loop back to the first component when we've reached the end. Next, we retrieve the component from the container's component array with the getComponent() method. We then check that component for its tabbability. If it is not suitable, we increment our tab position and get the next component. If a suitable component is found, we return its position. The caller then requests the focus on its behalf.

There is one side note to all of this: The Java 1.1 API will support tabbing, so you might just want to wait!

All of the code snippets are from the JifPanel class that I wrote as part of a Java class library. The library is called the Java Intranet Framework, or JIF. JIF is featured in my book, Developing Intranet Applications with Java, from Sams.net. You can download and use the JIF classes for free from http://www.netgeeks.com/jif.html.

About the Author
Jerry Ablan ([email protected]) is the manager of Internet/intranet Software Development at the Chicago Board Options Exchange. Jerry and his brother Dan ([email protected]), operate NetGeeks (http://www.netgeeks.com), an Internet consulting firm in Chicago, Illinois. Jerry is the author of Developing Intranet Applications with Java from Sams.net; the co-author of the Web Site Administrator's Survival Guide from Sams.net. He also was a contributing author to: Special Edition: Using Java (Que); Platinum Edition Using CGI, HTML, and Java (Que); and Intranets Unleashed (Sams.net).

	

Listing 1.

//*************************************************************

//* handleEvent  *
//*************************************************************

	/**
	* Event handler
	* @param event The event
	*/
	public boolean
	handleEvent( Event event )
	{
		//Handle tabs nicely...
		if ( event.id == Event.KEY_PRESS && event.key == 9 )
		{
			if ( event.target instanceof Component )
			{
				if ( !event.shiftDown() )
					focusForward();
				else
					focusBackward();
			}

			//I handled it...
			return( true );
		}

		//I don't want this...
		return( super.handleEvent( event ) );
	}

Listing 2.

//*************************************************************
//* focusForward  *
//*************************************************************

	/**
	* Sends the focus to the next component
	* @param c The current component
	*/
	public synchronized void
	focusForward()
	{
		//Go from our current position and find next widget...
		currentPos = findNextComponent( currentPos );

		//Now set the focus...
		getComponent( currentPos ).requestFocus();

		if ( getComponent( currentPos ) instanceof TextComponent )
			( ( TextComponent )getComponent( currentPos ) ).selectAll();
	}

Listing 3.

//*************************************************************
//* findNextComponent *
//*************************************************************

	protected int
	findNextComponent( int startPos )
	{
		int			i = startPos + 1;

		do
		{
			//	Check for a wrap...
			if ( i >= countComponents() )
				i = 0;

			Component c = getComponent( i );

			//	Skip anything disabled or labels...
			if ( c instanceof Label || !c.isEnabled() )
			{
				i++;
				continue;
			}

			//	I am the one!
			return( i );
		}
		while ( i != startPos );

		//	Wow, no more!
		return( 0 );
	}
 

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.