Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Over-riding the result of a failed validation on a textbox control

Status
Not open for further replies.

AndrewMozley

Programmer
Oct 15, 2005
621
GB
I have a data entry form with a textbox control, txtThis.

txtThis.value needs to be validated. So, if txtthis.value is not acceptable, the txtthis.valid() method returns .F., and the text box retains control.

However, if the user clicks on a button cmdExit, I would like this to over-ride the effect of txtThis.valid, and (in this case) close the form.

Is there a way of achieving this? That is : Can the valid() method detect that the reason that the textbox needs to be validated is that the user has clicked on cmdExit?
 
There is a way.

There are two special properties making a button a Cancel or a OK button:
1. Cancel = .T. (making it a cancel button)
2. Default = .T. (the contexthelp here says this is the button responding to ENTER)

Only one button on a form can have these properties .t., the last you set. If you set it in another button this automatically set's this .F. in the previous cancel/ok button

The behavior change is twofold:

I. Keys ESC and ENTER cause these buttons Click events
II. Clicking these buttons causes ESC or ENTER as virtual Keypresses

Because of that in any case you can check for LASTKEY() = 27 (ESC) or Lastkey() = 13 (ENTER) in any code involved, eg in Valid() and skip validation in that case.

If you were asking me how I would use this, then I'd say not at all, I'd recommend you don't use valid() at all, but validate the whole record just before or within a Save method. It is okay to use these specifications for the OK and Cancel buttons though to give users standard Windows Form behavior.

Bye, Olaf.
 
Just a further note:

The cancel button does nothing automatically, if you skip validation in Valid due to Lastekey()=27, then you also need to Tablerevert() in the cancel button, or replace the field with CURVAL() to keep it the way it's in the DBF, if it's not already saved. When you don't work with buffering, skiping validation doesn't stop the wrong value from being saved, unless it's a type mismatch or such a wrong value causing an error.

What needs to be triggered by a Cancel and Default/OK/Save button can vary very much and be very complex for forms maintining a hierarchy of data of course. Ideally you just call into the business logic and that should know how to handle cancel or save and how and what to validate. Don't put logic into the GUI.

Bye, Olaf.

 
Andrew,

Does your form have an explicit edit mode? In other words, do you have an Edit button which enables the controls to be edited, and Save and Cancel buttons to respectively save or cancel the edits?

If so (and assuming the underlying table is buffered), the easiest solution is to disable the Exit button while you are in edit mode. In your Cancel button, you will have a TABLEREVERT() followed by THISFORM.Refresh. This will get rid of the invalid data in the textbox. After the user clicks Cancel, the form will come out of edit mode. If the user then clicks the Exit button, the form will exit normally.

An alternative would be to write code in the form's QueryUnload. The code will check to see if anything has been edited. If it has, and if the form is still in edit mode, it will ask the user if they want to save the edits. If they say Yes, the validation will fire (which is what you want); if they say No, do a TABLEREVERT() and close the form.

Hope this makes sense.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
Thanks Mike and Olaf

My application is a fairly simple Sales Invoice application

Slightly simplified, the form has an (implicit) header section an (implicit) details section, a “Close” button” and a “Details/ To Header” button which (with suitable tests) switches between the two.

In the header the user enters a customer account, a date, an 8-char reference and net and gross values of the invoice. The details section is not enabled (nor fully visible) until the user has successfully entered the header.

When the user is entering the details a “Post” button is available, and it is when the user eventually clicks on this that the data which I have built up in a cursor are used to update several tables.

I need to validate several features of the header (e.g. reference must be unique and not blank). I had wanted to validate all the header fields immediately they have been entered (while they are fresh in the user’s mind) but I suppose it is not a big deal that I can check them when the users clicks on the “Details” button. If I understand Olaf correctly, this is the approach he would adopt

The same issue arises when the user is entering the line values into the grid. Slightly simplified, the columns are nominal account code, value, VAT code and Description. Now it may happen that as the user is entering the nominal account he realises that he would like to go back to the header (perhaps to change the invoice total value).

In this case he can only do that if he enters a valid nominal account code (or perhaps blank). I appreciate that I could get round this problem by have a separate “OK to accept line” button, and to do all the validation of the line when this button is pressed. Indeed I know that many applications work this way and have controls outside the grid for entering the line details. I had mainly wanted to work as I do, to follow the working of the application I am converting. There is a slight saving of space on the screen.

As always, I would be interested in your thoughts
 
I had wanted to validate all the header fields immediately they have been entered

Can't you use the Valid Method of the individual Header text boxes to Validate the entries immediately they have been entered ?

The same issue arises when the user is entering the line values into the grid.

The Details Grid Column's text boxes also have a Valid Method that is available for use to possibly Validate entries immediately they have been entered

And any of those Valid Methods can 'branch' out to common Detail Line Validation methods (example: ThisForm.ValidateDetailLine or ThisForm.ValidateHeaderEntries) so that complex validations need only be developed and written once.

Good Luck,
JRB-Bldr




 
Andrew said:
I had wanted to validate all the header fields immediately they have been entered (while they are fresh in the user’s mind) but I suppose it is not a big deal that I can check them when the users clicks on the “Details” button. If I understand Olaf correctly, this is the approach he would adopt

I would also do it that way.

The advantages are: (i) you don't force them to do the data entry in any particular order; and (ii) they are free to leave an item blank for the moment, then come back and fill it in later. Doing it this way also means that you can validate one field in relation to another if necessary (e.g field 1 must always be a date, and must be earlier than field 2).

Andrew said:
The same issue arises when the user is entering the line values into the grid. ... In this case he can only do that if he enters a valid nominal account code (or perhaps blank). I appreciate that I could get round this problem by have a separate “OK to accept line” button, and to do all the validation of the line when this button is pressed. Indeed I know that many applications work this way and have controls outside the grid for entering the line details.

I never use a grid for data entry. It's a lousy interface. Better to have controls outside the grid; let them enter the data into those controls and click an OK button; then add the row to the grid with the data that has just been entered. Similarly for editing existing grid rows. And give them a delete button to remove rows (if permitted).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
>Now it may happen that as the user is entering the nominal account he realises that he would like to go back to the header >(perhaps to change the invoice total value).
>
>In this case he can only do that if he enters a valid nominal account code (or perhaps blank).

That is the problem, because the validation forces him to enter a code, correct? Why bother with it, if you have buffered all data or even store it in seperate cursors, whcih are your self made buffer.

I'd always want to be able to shift around and change tabs of a form.

You could use the valid() event to immediately highlight textboes with a background color of a light red, and still return .t. to let a user leave the control. That wouldn't hurt to do, would it?

You only need a harsh Valid, if your controls are bound to the table unbuffered and you need to prevent wrong values to go into a dbf. Even more so, if there are referential integrity rules, field and table rules in a DBC. But anything else can be delayed and detecting an invalid field you can SetFocus to that page and control, scroll to that record etc.

Forcing correct values directly forces a user too much.

Think alone of the example Mike gave with two date fields, one needing to be earlier than the other. Imagine you want to type in 01/01/2012 to 12/31/2012 and wrongly type in 01/01/2013 in the first field, which validates nevertheless, but are forced to enter some date in 2013 or later into the second field, before you can correct the first field to then come back and correct the second field. It would be better, if you could enter 12/31/2012 even though it's earlier than 01/01/2013, because 12/31/2012 is the value you need and the 01/01/2013 is the error.

In this case you can highlight both date fields and the user can decide what needs to be corrected.

Bye, Olaf.
 
Despite my saying that you could use the Grid Column's Text box Valid Method's to validate Detail data entry, I too strongly advise against using the Grid itself as a Data Entry tool.

It is good for displaying data that has already been entered, but often problematic for data entry itself.

One way to separate the Header from the Detail might be to use a Pageframe - one Tab page for the Header info and a separate Tab page for the Detail
And if you did that you could perform the Header validation before allowing entry into the Detail Tab page.

But if you did it this way, I'd still recommend, like others above, to use Text Boxes to enter the Detail data and then Submit/Enter those values into the Grid record when they have been validated.

Good Luck,
JRB-Bldr
 
Mike,

what I described with backcolor highlighting I'd rather call soft, mild or perhaps lenient validation. With harsh validation I mean the type of validation not allowing a user to leave a control, unless it's value validates. The highlighting could also be done from the start, marking fields which need input. That would be another reason to do that in a central validation method, not in each individual valid event. Not only because valid is first executed after the first data entry in a field, but also because checks involving more than a single field and overall code to highlight controls would better be maintained in a single method.

Bye, Olaf.
 
Thank you all for your feedback. I can see that there are advantages in consolidating the validations; although in this case there are not validations which are based on more than one control (as in the range of dates scenario, Olaf, where I have seen several applications which run into the problem you have described).

Mike Lewis said:
I never use a grid for data entry. It's a lousy interface

These are strong words, Mike, so I shall pay attention! For the time being I may continue to enter data into my grid, but will be prepared to admit that I was wrong if it all becomes unmanageable. In my case (in the previous version) I had the convention that the entry of a blank nominal account code was interpreted as an instruction to delete the line.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top