|
Jim Douglas Software Engineer Contractor |
|
nput validation seems like the simplest thing in the world: A user enters a value into a field and the program decides whether
to accept it. Character-mode programs have been handling it like this for decades:
The INPUTE verb improves on that, allowing masking and using input validation instead of a secondary test:
In either case, the concept is the same: The user cannot proceed until he or she enters a legal value.
How does this translate to an event-driven GUI program?
GUI Validation in BBj
The intuitive approach is to validate the input when the user tries to leave the field, forcing valid input before continuing.
Here is an example:
Though this example contains more code than the equivalent character-mode program, it is comparable. The user must enter "S,"
"P," or "F" in the first field before proceeding to the second field. What could be wrong with this approach? As we add more
fields to the screen, each with its own validation rules, the problems become clear.
Validation in BBj 4.03
The example OldValidation.txt creates the dialog box in Figure 1 that contains the four controls in Figure 2:
|
Figure 1. OldValidation.txt results. |
| CONTROL |
COMMENTS |
| "To""field |
Requires an "@" character for the e-mail address to be valid |
| "Subject""field |
Accepts any non-blank input as valid |
| [OK] Button |
Validates the entire screen, then does something with the data |
| [Cancel] Button |
Leaves this window and bypasses validation, even if a control contains invalid data |
Figure 2. OldValidation.txt controls. |
How well does this work?
After clicking in the "E-mail Address" field, then clicking in or tabbing to the "Subject" field, the address field loses
focus and the subject field gains focus. This triggers the ON_LOST_FOCUS event
handler, AddrValidation, for the e-mail address field. The e-mail address, lacking the required @ symbol, is invalid, so the
program forces focus back to the e-mail address field. The user cannot proceed until this field contains an "@." So far, so
good.
Clicking the [OK] button validates the e-mail address field, then the subject field. If either field is invalid, BBj® forces
focus back to the invalid field for correction. Then the user can proceed.
Clicking the [Cancel] button also triggers an ON_LOST_FOCUS event for the control that had focus. This is potentially a
problem because clicking [Cancel] should skip all validation and let the user out. The program allows for this scenario by
including this special rule in each of the validation routines: If the [Cancel] button has focus, consider the control to be
valid. This solves the problem, but at the cost of complicating the validation routines.
That all sounds great, but there is a serious problem with using the loss of focus event. To see the problem, run this
program, click in the "Subject" field, clear its contents, then click in the "E-mail Address" field. This is what happens:
- The "Subject" field loses focus.
- The loss of focus in the "Subject" field triggers the validation logic for the "Subject" field.
- The subject is invalid so BBj forces focus back to the "Subject" field.
- Since focus had already moved to the "E-mail Address" field, it now loses focus.
- This loss of focus triggers the validation logic for the "E-mail Address" field.
- The e-mail address is invalid, so BBj forces focus back to the "E-mail Address" field.
- And so on.
The program is now in an infinite loop, jumping back and forth between the two fields.
Validation in BBj 5.0: Veto Power
In previous versions of BBj, field-level validation was very difficult because it was impossible to stop the user from moving
out of a field. Forcing the user back to an invalid field after some other control gained focus caused a potential cascade of
side effects. That cascade could include many different events and state changes, for example by clicking a radio button or
check box. Changes like this were extremely difficult to reverse.
In BBj 5.0, loss of focus is a vetoable event, meaning the user can only move out of a control if it contains valid data based
upon whatever rules are defined in the application. Giving the developer a way to stop the user from leaving the control until
it is valid eliminates the potential cascade of side effects. For a complete example, see NewValidation.txt.
Compare these two approaches to field-level validation shown in Figures 3a and 3b.
|
|
Figure 3a. Field level validation comparison, BBj 4.03 |
Figure 3b. Field level validation comparison, BBj 5.0 |
BBj 4.03 reacts to the loss of focus. If it determines that the e-mail address is invalid, it forces focus back to the address
field.
BBj 5.0 reacts to the attempted loss of focus. If the data is invalid, the developer vetoes the attempted loss of focus by
calling addr!.accept(0), which flushes the event queue and keeps the user in the e-mail address field. If the
data is valid, the developer approves the loss of focus by calling addr!.accept(1). While the program is in the
validation subroutine, BBj locks the window. The window stays locked until the application calls
control!.accept(boolean).
Making the loss of focus vetoable eliminates all of the side effects caused by using the loss of focus event.
Form Validation
Previous versions of BBj handled form validation in the event handler for the [OK] button. BBj 5.0 adds a new form validation event as
shown in the example below:
There are two benefits to this approach:
- While the FormValidation subroutine is validating the form, the window is locked and the user is prevented from making any
changes until the call to
control!.accept(boolean) accepts or rejects the data. This eliminates the infinite loop
problem caused by forcing focus back and forth between two invalid controls, and it removes the need to reverse state changes
caused by clicking in controls like check boxes or radio buttons.
- The program is more modular by breaking validation into two new separate subroutines. The FormValidation subroutine is
responsible for validation while the OK subroutine is responsible for everything else (e.g. updating the data to a file). BBj
invokes the OK subroutine only after the FormValidation subroutine accepts the form.
It Works With GUIBuilder
When adding form and field validation into programs originally developed in Visual PRO/5® or GUIBuilder®, it is not
necessary to rewrite existing programs to use callbacks and PROCESS_EVENTS. The sample NewValidation2.txt processes the same
form using an event loop instead of callbacks. The excerpt from that sample (see Figure 4) shows that event code "v"
triggers field-level validation and event code "V" triggers form-level validation.
|
Figure 4. Event loop code excerpt from NewValidation2.txt. |
To incorporate validation into a GUIBuilder-generated program, add the various callbacks for ON_FORM_VALIDATION and ON_CONTROL_VALIDATION to
the initialization routine, specifying any string for the callback subroutine (here we just used "") and create the
corresponding Form Validation and Control Validation event handlers for those controls.
But Wait, There's More!
While the most important feature of BBj 5.0 control validation is the ability to veto loss of focus, there are other
significant improvements that are also very useful.
Cancel!.setCausesControlValidation(0) specifies that a control such as the [Cancel] button does not trigger
validation. This simplifies the validation routines since they do not have to explicitly check for the [Cancel] button.
Control!.getValidationText() retrieves the current text from the control without incurring additional network
traffic. This improves performance in a distributed environment, but field-level validation, by its nature, creates extra
network traffic. In a high-latency-distributed environment, applications are significantly more responsive when performing
validation at the form level, by clicking [OK]. Though this approach differs from legacy character-mode applications that
usually validate fields immediately, it is familiar to users who run Web applications. Normally, in Web-based applications,
the user fills in a complete form, then clicks [Submit] to validate the entire form. BBj offers both kinds of validation so
you can choose the best method for your environment.
- The new data-aware grid event, ON_GRID_ROW_VALIDATION, validates grid row data changes before they are updated to the
database. This event works like the control and form validation events: The developer accepts the update by calling
Grid!.accept(1) or rejects the update by calling Grid!.accept(0).
The code fragment in Figure 5 (from the GridValidation.txt sample) demonstrates how to use grid row validation.
|
Figure 5. Grid row validation code excerpt from GridValidation.txt |
Summary
Field and form validation is a valuable enhancement to BBj. As this article shows, it is easy to incorporate validation into
new applications or retrofit it into existing applications whether originally developed using Visual PRO/5, GUIBuilder, or
previous versions of BBj. This enhancement is now available in BBj 5.0.
Download the samples referenced in this article.
In the online BBj 5.0 documentation, enter "Validation"
in the index for a listing of related topics.
|