Wiki Home

Skip Valid On Exit

Namespace: Wiki
In a Form, I have several textboxes that are validated against a table. The only logical way to set up the screen is for one of them to have the focus when you enter the form or after a save and ready for the next input (this textbox determines what all the rest have in them [e.g., the order number]). I also have a standard EXIT button which Thisform.Release()s.

When I click the EXIT, the Valid() on the order field fires first and I must validate it before I can exit. My current work-around is to set the form's Key Preview on and check for ESCAPE and release.

How can I know in the Valid for order what event caused the valid to fire (i.e., the exit click) so I can conditionally skip the valid and let the form release?

I know I have seen this somewhere but can't remember.


David Brandon

There are a number of advantages of using an Exit button with the Cancel property set to .T. and checking for LastKey() = 27 in the Valid events of all of your control classes. One is that with Cancel set to .T. clicking the button is the same as pressing Escape so checking for 27 (Escape) as the LastKey() will tell you if the Exit button has been clicked. Secondly with Cancel set to .T. pressing Escape will click the button and fire its Click event thusly allowing you to give the user an expected functionality for the escape key.

In my control classes the beginning of the Valid event is;

IF LastKey() = 27
   Keyboard "{CTRL+A}"

The keyboard of CTRL+A is to change the value of LastKey() from 27. This is because if the user clicks the exit button and then only uses the mouse, lastkey() will remain 27 until some other key is pressed. Doing the keyboard changes lastkey from 27 so the only way it can be 27 again is by pressing escape or clicking a button that has Cancel set to .T.


If your [Exit] commandbutton has its .Cancel property set to .T., then you could simply check if LastKey() is set to 27 (Escape) in which case you would know that the user clicked on [Exit] and you should, in response, skip the VALIDation.


Art Bergquist

See also January 1999 FoxPro Advisor Tips section for a more detailed tip by Art Bergquist involving MDOWN() and SYS(1270).

OK - Here's what I really meant the first time around. :P

From the SET EVENTTRACKING TO logfile:


The WHEN event of the control receiving the focus fires before the LOSTFOCUS event of the control losing the focus. If you can move your validation code to the LOSTFOCUS event, you could check a form property (set in the WHEN event of your other controls) to see if the control should really lose the focus or not. To prevent the control from losing the focus, use NODEFAULT in the LOSTFOCUS event. - William Fields

Thanks William, I think this is what I am looking for. Moving out of the valid shouldn't be a problem and also lets you use setfocus etc. David Brandon

In our framework every VALID event has the following structure:

local lValid

if thisform.userEvent()
    return .T.

lValid = dodefault()
if lValid
    *-- put the valid code here

return lValid

userEvent() checks if the user clicked a toolbar button, switched to another form, etc.

Nicola Marangon
Nicola, this looks good but what is userevent ? I can't find it in the help or hackers guide. If it is a custom method, you still have to have a way t determine if an event happened and if so which. Actually that could be my question, how can you capture that an event happened and if so what it was ? David Brandon
userEvent() should be a custom method of the form and it could look like this:

with this
return .lClosing or .lCancelling or .lFinding or .lLeavingControl or <> .name

All properties are owned by the form and can be changed clicking a toolbar button or programmatically. It's a simple approach, but it works quite well.
Nicola Marangon

Another approach is ďjust donít do thatĒ. What I mean is donít ever return .F. from a valid. I would rather let the user know the entry isnít perfect, and why it isnít, but let them proceed.
Imagine if when you used a word processor it didnít allow further typing until the current word was correctly spelled. That would really be bad for me. Word, for example, indicates the misspelling by a saw-toothed red line and lets the user proceed. That is what I prefer to do when providing for data entry. (Make it work more like spell check.)
The valid fires and loads the problem message in a validation object associated with the business object. In some cases I save the error message in the same table with the data. In either case when a problem is discovered, the backcolor of the control turns yellow so the user can see thereís an issue. When the control has focus, a status bar, tooltip, or rightclick; take your pick, can show the user what the issue is.
When the user desires to close a form, I first check it the user has made any changes, and if not, I donít validate or worry about saving. This is my UserModified method. It ignores changes in a new record that were done to prepare the record for inputóprogrammatic changes, defaults and the like.
Prior to a save, the validation object checks the record and determines if it is perfectly valid, not quite valid but worthy of being saved, or fatally flawed and unable to be saved.
Charlie Schreiner

Well Charlie, that works if your building a word processing app, we're talking text boxes here, that in many cases it's very critical what the user enters and validation control of that text should not be left to the discretion of the user. If you don't clean it up at the beginning, you'll have loads of bad data to clean up later. It's better to return .F. from a valid and just check for lastkey() = 27, that covers the user pressing Escape or clicking the cancel button, add the valued for the keyboard press, such as ALT-L (if your hot key for Cancel is assigned as ALT-L), then check lastkey() = 38. It's far more logical to limit the amount of "Garbage In" when you can and that's at the time of data entry. Anyone that writes a lot of data entry apps knows that.


Category Questions
( Topic last updated: 2013.11.23 11:08:47 PM )