Simple TextField
       

I am assuming you have got through the initial Spotlet and SpotletEvent Handling examples, and now you want to add something other than a Button to your screen. This example will show how to use a TextField. TextField creates a thread for the caret to blink, accepts key input (including delete and backspace) and allows for only upper case entry

Ah, you say I know how to use a TextField from AWT, how different can it be? Well, as I've mentioned, if you want AWT functionality, try using the kAWT project, because you will quickly see that the TextField provided in the KVM is a distant relative from the AWT version.

First, you'll find that in up to version EAv0.2, the documentation for this class is...well...lacking. I had to do a little trial and error to find out how to even use the constructor properly. The constructor for this class is:

     TextField(String labelText, int x, int y, int w, int h)

When you look at the detailed description, you find that the x and y values are the upper left x and y position of the TextField, these are in pixels. The width (which includes the label) and height values are also in pixels, although they are not documented as such. If you've ever tried to line up JLabels with JTextFields, the inclusion of the label in the TextField is actually quite nice. In addition, the sizing of the the label with the field will help with any aligning of multiple fields, since you are explicitly controlling the right and left pixel boundries of the TextField. For example, the code

     newText = new TextField("Name", 10, 80, 120, 15);

produces the following on the screen:

Sample TextField

Note that the label text has a semi-colon inserted after it, and the field itself is shown as a series of underlining dots. An interesting feature(?) is that TextField a is fixed width input area. It does not support scrolling, and will only accept input until the input text reaches the field width. Since the Font on the Palm Pilot is not constant width, it is quite possible for the TextField to block further input, until a narrow character (such as an "i" is typed), where it is then squeezed in.

Once you have the TextField constructed, you need to have it respond to events. The API states that setFocus() method will give the textfield "focus". The registered Spotlet actually has focus. This method kicks off the caret thread to get the caret to blink. Unlike the AWT/Swing which has a focus manager, you need to manage the focus in your Spotlet. In this case, you need to respond to a penDown() event by explicitly calling the setFocus() method on the TextField.

    ...in constructor...
    newText = new TextField("Name", 10, 80, 120, 15);

    public void penDown(int x, int y) {
	if (exitButton.pressed(x,y)) {
	    System.exit(0);
	} else if (newText.pressed(x,y)) {
	    if (!newText.hasFocus) {
  	       newText.setFocus();
            }
	} else {
  	    newText.loseFocus();
	}
    }

One of the final things to notice is that when the focus is set, the cursor is always set to the last character in the TextField. You can't place the cursor mid-way in the text, it only operates at the end of the text. Also note that the TextField can only set the focus once on itself. If you try to set the focus while it already has it, the program will crash.

Note: As of EAv0.2 and the POSE emulator v2.1d29, selecting a TextField which already has focus produced an emulator error. This same set of actions produces Fatal Exception on the Palm Pilot itself


The full source code of the example


In this example, I have a single TextField which is accepting input, and a second String which echoes the input when the user selects something other than the TextField. This example is quite similar to the others, with the key code snippets listed below

    TextField newText;
    String output="";

    public SimpleTextField() {
	
	// create the button
	exitButton = new Button("Exit",139,145);
	newText = new TextField("Name", 10, 60, 120, 15);
	paint();
    }

    private void paint() {
	g.clearScreen();
	// Draw GUI controls and buttons
	newText.paint();
	g.drawString("You entered: " + output, 10, 100);
	exitButton.paint();
    }
    
    /**
     * Handle a pen down event.
     */
    public void penDown(int x, int y) {
	if (exitButton.pressed(x,y)) {
	    System.exit(0);
	} else if (newText.pressed(x,y)) {
  	    newText.setFocus();
	} else {
	    if (newText.hasFocus()) {
		output = newText.getText();
		if (output==null) output = "";
		newText.loseFocus();
		paint();
	    }
	}
    }

    public void keyDown(int keyCode) {
	if (newText.hasFocus()) {
	    newText.handleKeyDown(keyCode);
	}
    }

Notice the explicit handleKeyDown() method call in the keyDown() method of the Spotlet. This is because you need to redirect the key event from the Spotlet to the TextField when it has focus. Also note that when a penDown() event occurs outside the TextField, the text is extracted from the TextField, stored in the output variable, and then loseFocus() is called on the TextField to release focus and stop the Caret thread. When run, the example looks like this: