| Developer's Daily | Visual Cafe Education |
| front page | java | perl | unix | DevDirectory |
Introduction
In Part 1 of our FinancialTextField Component article last month, we discussed the need for a FinancialTextField component for use in Internet commerce applets. Our review of Internet applets showed that most applets made no effort to control the user input into financial data-entry fields.
For instance, in the world of electronic banking, where you can transfer money between various bank accounts, we found that you can type something like "One million" into the withdrawal field of an applet, where you should only be able to enter financial values - float values with two positions after the decimal, like "1250.00" or "9123.95".
Of course good applets always validate user input before trying to use the data, so the bad input never propagates further into the applet. However, a downside of this approach is that you must prompt the user at some point with an "input error" message.
Another approach is to minimize data-entry errors by letting the user
enter only valid financial values into the data-entry field to begin with.
Not only does this approach eliminate errors, it can also make your applet
look more polished. That's the approach we'll present in this article,
as we complete our development of a FinancialTextField data-entry
component.
A quick review
At the conclusion of last month's article, the end-user was limited to entering only numeric digits and decimal characters into the FinancialTextField component. This is a good start, but we noted that it suffers from at least two primary limitations:
public boolean keyDown(Event evt, int key) { |
| Listing 1: | Last month's keyDown() method limits the characters a user can type into the FinancialTextField component. |
If the user keystroke is not one of these valid values, keyDown()returns a value of true to the handleEvent() method. This tells handleEvent() that the user keystroke has already been handled, and no further event handling is required. By doing this, we ignore keystrokes that we consider "bad". This simple method was okay for our first-cut approach, but still leaves us with the two errors identified above.
In this article we'll improve our approach by creating a new method,
named validateKeystroke(), that tests the user keystroke according to the
rules we define, and lets the user enter only valid numeric values into
the FinancialTextField component.
Modifying the keyDown() method
Before creating the validateKeystroke() method, let's look at how it should be called from the keyDown() method. By doing this, we'll understand what behavior the validateKeystroke() method needs to provide.
Looking at the two problems identified earlier, we know that we'll need to validate the user input any time the user tries to enter a numeric or decimal character. Because these characters are acceptable only under certain conditions, we'll call the validateKeystroke() method any time one of these characters is entered.
If the validateKeystroke() method returns a value of true - meaning the keystroke passes our tests - we'll hand the keystroke over to the super.keyDown() method for further processing. However, if validateKeystroke() returns a value of false - meaning that it has violated one of our rules - we'll just ignore the keystroke attempt.
We know that we need to call validateKeystroke() when we receive numeric and decimal characters, but what about the cases when another valid keystroke occurs, such as the [Backspace], [Del], [Enter] or [Tab] keys? Because these keystrokes don't result in the user creating an invalid financial value in a text field, you don't have to validate them. Instead, you can just pass them along to the super.keyDown() method.
Understanding these possibilities, the modified keyDown() method is
shown in Listing 2. In this listing, validateKeystroke() is
called any time a user keystroke is a numeric digit or a decimal character.
Otherwise, if the user enters a keystroke such as the [Backspace],
[Del], [Enter] or [Tab] keys, the validateKeystroke() method is skipped,
and the super.keyDown() method is called. Any other keystrokes the
user attempts are ignored.
public boolean keyDown(Event evt, int key) { |
| Listing 2: | The new keyDown() method calls validateKeystroke() to test the input of numeric and decimal characters. |
Now that we know what the new keyDown() method will look like, we'll
create the validateKeystroke() method to fit into this structure.
Creating the validateKeystroke() method
The validateKeystroke() method will apply our keystroke tests to the numeric and decimal characters the user enters into the FinancialTextField. If the keystroke is considered valid, we'll return a true value. If the keystroke fails any of our tests, we'll return a false value instead, indicating that the attempted keystroke is not okay - it would result in an improperly formed financial value.
In the validateKeystroke() method, four tests are applied to the user keystroke to determine whether it is "acceptable". These tests cover four data-entry conditions that can result in an invalid financial data-entry field.
The first two tests have been discussed already:
2. Allow only two numeric digits to be placed to the right of a decimal.
4. Control how a decimal character is handled when the user first
highlights a range of characters.
The first test condition restricts the user to entering only one decimal character in the FinancialTextField component. Because the event handler captures the keystroke before it enters the text field, this condition is easy to enforce.
When the validateKeystroke() method is called, we'll get the text string currently in the FinancialTextField with the getText() method. If there is already a decimal character in the string, we'll return a value of false to the calling routine, indicating that the keystroke is not okay - a second decimal character is not allowed.
The code to accomplish this task in the validateKeystroke() method is shown below:
private boolean validateKeystroke(int key) {
String currentText = getText();
// Test 1
int decimalPosition = currentText.indexOf('.');
if (key == DECIMAL) {
if (decimalPosition >= 0)
return false;
}
}
Because Test 1 applies only when the decimal key is entered by the user, the outer if/then test runs the inner test only when the decimal key is hit:
Test 2: Allowing only two characters to the right of the decimal
The second test we'll apply in validateKeystroke() restricts the user
to entering only two numeric digits to the right of a decimal. The
best way to create this code is to first look at how it would be written
in pseudocode:
The next step is to turn this pseudocode into Java code:
if (key > 47 && key <
58) {
if (decimalPosition >= 0) {
if (cursorPosition
> decimalPosition) {
if ((strLen-decimalPosition) > 2)
return false;
}
}
}
This method is implemented in the TextComponent class, the superclass
of the TextField class. It's normally used to determine the starting
location of a highlighted section of text. I've also found it to be an
indicator of what I call the cursor position - the position of the
on-screen cursor as the user is typing. (You'll also see this referred
to as the caret position.)
Test 3: Inserting a decimal into an existing string
The third test covers the case in which the user attempts to enter a decimal character into an existing string of numeric digits. Let's say for instance that the user entered the string "12345", and then tried to enter a decimal between the 2 and the 3. Because this would result in an invalid financial value, it can't be allowed. By our interpretation, a decimal can only be entered into one of the last three positions in the string, because it's only legal to have two numeric digits to the right of the decimal.
Writing this test as pseudocode results in something like the following:
Converting this to Java results in this test condition:
Test 4: Insertion of a decimal when a range is highlighted
The fourth and final test in the validateKeystroke() method is applied when the user highlights a range of characters in the FinancialTextField component, and then attempts to enter a decimal character onto the selected text.
An example of this is shown in Figure 1, where the characters
"34.56" are highlighted. If the user hits the decimal key at this
time, the keystroke should be allowed. However, in another example,
if the characters "34" are highlighted and the decimal key is hit, the
keystroke should not be allowed, because this would result in two decimals
in the field.
|
![]() |
A pseudocode description of Test 4 looks like this:
How do you determine if the user has highlighted a section of text in a TextField component? The code snippet below shows how to determine whether a user has highlighted a range of text:
boolean rangeSelected;
if (selStart != selEnd)
rangeSelected=true;
else
rangeSelected=false;
Placing that snippet of code at the top of our method, here's the Java code that implements Test 4:
Fixing the previous test conditions
In the three previous tests, we didn't check to see if the user highlighted a range of characters as part of our test conditions. Is this an error? You bet it is.
Looking at the first three tests, you'll see that each condition assumes that a range of characters is not selected. In fact, our discussion did not consider the possibility of a range of characters being highlighted until we discussed Test 4.
Fortunately, fixing the first three tests is a simple matter. Because each of these tests are designed to be used only when a range of characters is not selected, we'll fix the tests by adding this simple test condition around each test:
}
The final code
Combining the four tests together results in validateKeystroke() method shown in Listing 3.
private boolean validateKeystroke(int key) { |
| Listing 3: | The validateKeystroke() method applies four tests to the current user keystroke. |
Conclusion
The FinancialTextField class can be used to create data-entry prompts in commerce applets. This class offers the advantage that only numeric and decimal characters can be entered into your financial data-entry fields, in the proper format, thereby reducing the opportunity for input error.
In developing the FinancialTextField class we examined several low-level user interface concepts. First, we examined the process of creating a keyDown() method that is invoked by the event handler. Next, we showed how to control which keystrokes the end user is allowed to type by modifying keyDown(). After that, we showed how to validate those keystrokes according to our customized rules before they're entered into a TextField component. In our keystroke-validation algorithm we demonstrated the process of determining the position of the cursor in a TextField component, and showed how to determine when a range of characters has been selected in a text field.
Hopefully you can use the FinancialTextField component in your commerce applets, and also use these techniques in developing other customized components.
[Note - This article first appeared in ZD Journals Visual Cafe Developer's Journal. The article is reprinted here with their permission. The author now works for Developer's Daily.]
Copyright © 1998 DevDaily Interactive, Inc.
All Rights Reserved.