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 TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

SetFocus not working

Status
Not open for further replies.

SitesMasstec

Programmer
Sep 26, 2010
508
Brasil
Hello, colleagues!

I created a form, which has a field for date, which must not be blank: the user must type a date.

If the field for the date LostFocus and is blank the field becomes red and the cursor have to stay in the field (please see bellow).
RelReservas4Data.jpg

But when I run it, if I leave the field blank (with no date), it only becomes red and the cursor goes to next field, instead!

What is wrong?

RelReservas4DataRun.jpg
 
Code:
If this.Value = CTOD("  /  /    ")
    this.BackColor = RGB(255, 128, 128)
    this.SetFocus
    RETURN .F. && This stops the cursor from moving to the next field
ELSE
    this.BackColor = RGB(255, 255, 255) && Reset to default color if valid
    RETURN .T.
ENDIF

In FoxPro, RETURN .F. and RETURN .T. are used to indicate the result of a function or method, particularly in events like Valid.

  • RETURN .F. (False): When used in a Valid event, it tells FoxPro that the validation has failed. As a result, the focus will remain in the current field, preventing the cursor from moving to the next control. This is commonly used to enforce validation rules, ensuring that the user cannot leave the field until they enter a valid value.
  • RETURN .T. (True): This indicates that the validation has passed successfully. When RETURN .T. is executed in a Valid event, FoxPro allows the cursor to move to the next control in the form, as there are no issues with the entered value.
In general, RETURN .F. and RETURN .T. allow developers to control the flow of form navigation, making it easy to enforce input requirements before allowing the user to proceed.
 
Hello, colleagues!

I created a form, which has a field for date, which must not be blank: the user must type a date.

If the field for the date LostFocus and is blank the field becomes red and the cursor have to stay in the field (please see bellow).
View attachment 834
Hello, colleagues!

I created a form, which has a field for date, which must not be blank: the user must type a date.

If the field for the date LostFocus and is blank the field becomes red and the cursor have to stay in the field (please see bellow).
View attachment 834

But when I run it, if I leave the field blank (with no date), it only becomes red and the cursor goes to next field, instead!

What is wrong?

View attachment 835


But when I run it, if I leave the field blank (with no date), it only becomes red and the cursor goes to next field, instead!

What is wrong?

View attachment 835


Like other said, use VALID() instead, check if the field is blank there and if it is, use NODEFAULT()
 
I agree with the other replies but I'd like to clarify that LostFocus always fires after Valid, which is means LostFocus will not execute until Valid allows you to leave the box.

The fact that it turned red means that it did lose focus when LostFocus detected the blank date.

What is more of a puzzle is that the SetFocus didn't push it back. I'm sure it has something to do with the fact that moving focus is not binding, there is nothing that implicitly blocks the cursor from leaving, but Valid always locks you into the box until it returns .T.

PS, you should use IF EMPTY(This.Value) instead of converting it to a string and comparing it to an empty date string. It's not just faster and cleaner code, but it's always accurate because the empty date " / / " can vary depending on the settings for dates like century on, and changing the delimiter from / to something else.
 
SoftwareRT: I put your provided code in the LostFocus event and the result was the same: the mouse cursor went to the next field.

Martinkk: I put the code in the Valid event only and this was the result:

RelReservas4DataRun2.jpg
 

Attachments

  • RelReservas4DataRun2.jpg
    RelReservas4DataRun2.jpg
    301.1 KB · Views: 0
I agree with the other replies but I'd like to clarify that LostFocus always fires after Valid, which is means LostFocus will not execute until Valid allows you to leave the box.

The fact that it turned red means that it did lose focus when LostFocus detected the blank date.

What is more of a puzzle is that the SetFocus didn't push it back. I'm sure it has something to do with the fact that moving focus is not binding, there is nothing that implicitly blocks the cursor from leaving, but Valid always locks you into the box until it returns .T.

PS, you should use IF EMPTY(This.Value) instead of converting it to a string and comparing it to an empty date string. It's not just faster and cleaner code, but it's always accurate because the empty date " / / " can vary depending on the settings for dates like century on, and changing the delimiter from / to something else.
Yes, that is all correct. Valid() is better but LostFocus() will work as well. I think the problem with the original code is that there is no test at all. And, yes, IF EMPTY() without CTOD() should work fine. Another issue I can see with all that is that returning .F. from either method will lock the field until user will enter something, which is not very professional. We have a ton of these validations in our software and normally we validate this code on the click of the action button. This is a design so whatever but it has to be a test of some sort. There is a code for that from SoftwareRT user even though THIS.SetFocust() cannot be issued from within VALID() as the test shows. If that was me, I would show them and error message, if the field blank but would allow the cursor to leave the field but I would block any actions when everything has been entered
 
Solved, following your advices:
I put in the Valid event:
Code:
IF EMPTY(This.Value) 
    this.BackColor = RGB(255, 128, 128)
    RETURN .F. && This stops the cursor from moving to the next field
ELSE
    this.BackColor = RGB(255, 255, 255) && Reset to default color if valid
    RETURN .T.
ENDIF

And then in the LostFocus event:
Code:
IF this.Valid()=.F.
    this.SetFocus
ENDIF

Then it works fine: when I left the field empty it becomes red and the mouse cursor stays in it. I only have a doubt:
this test IF this.Valid()=.F. is a normal command in VFP?
 
Not my code but check the VALID() in the LostFocus() is a bit weird, I don't think you need it. If VALID() = .F., the cursor will never get into the LostFocus() anyway
 
I agree with igorsandler. Not letting users out of a field can cause problems and irritates them. You can color all the fields that need to have a value or in some other way indicate they are required. Do a form level validation, with a list of each field that is failing the validation. I use a method called ValidateRecord and if it does not return true, I don't let the save proceed.
 
SoftwareRT: I put your provided code in the LostFocus event and the result was the same: the mouse cursor went to the next field.

Martinkk: I put the code in the Valid event only and this was the result:

View attachment 837
There is no need to use SetFocus. It will remain in that box until it returns a true valid either way.

Just use:

Code:
if empty(this.value)
   ** optionally set the color to red.
  return .f.
else
   ** optionally set the color back to white.
   return .t.
endif

If the box is empty, it will return .f. and the cursor will not leave the box. If you want to warn the user that they can't leave it blank, but some indicator before returning .f. such as a MessageBox.
 
I agree with igorsandler. Not letting users out of a field can cause problems and irritates them. You can color all the fields that need to have a value or in some other way indicate they are required. Do a form level validation, with a list of each field that is failing the validation. I use a method called ValidateRecord and if it does not return true, I don't let the save proceed.
I'm not a fan of locking people into a field either, but in many cases, something like a date is essential to data integrity.

In cases like that, if empty is not allowed or if they enter something wrong, I'll populate it with something like the previous value or a default such as today's date. Then rather than leave it out, it will have a valid entry.
 
I'm not a fan of locking people into a field either, but in many cases, something like a date is essential to data integrity.

In cases like that, if empty is not allowed or if they enter something wrong, I'll populate it with something like the previous value or a default such as today's date. Then rather than leave it out, it will have a valid entry.
What about popping up a message to get user's attention, then return to the date field after user acknowledgement ?
This is better than simply blocking the cursor movement with a red hi-lite, IMHO.
 
What about popping up a message to get user's attention, then return to the date field after user acknowledgement ?
This is better than simply blocking the cursor movement with a red hi-lite, IMHO.

I mentioned the MessageBox in a prior post, but in some cases you simply can't leave critical fields blank so you need to do more than just warn the user.

If a required field like a date is missing for booking a trip or for an accounting record, the record is useless, so you need to either prevent them from saving, or replace it with a default because as annoying as blocking their cursor may be, having a reservation without a date is not an option.
 
If I want to keep the focus in a textbox under a certain condition, I usually put all code in the LostFocus event.

For example, when a value is entered and it has to have a minum length

Code:
*** Lostfocus
IF !EMPTY(this.value) AND LEN(this.value) < 5
   MESSAGEBOX("Please correct, lenght must be over 5.")
   NODEFAULT
   this.setfocus()
ENDIF

You also have to to be carefull with the close button of the form, you have to add code to the QueryUnload() event or a button to release the form, because when the close button is clicked, the form can close although the above code.

Code:
*** forms load
ADDPROPERTY(thisform, "doNotClose", .F.)

*** textbox lostfocus
IF !EMPTY(this.value) AND LEN(this.value) <5
   thisform.doNotClose = .T.
   MESSAGEBOX("Please correct, lenght must be over 5.")
   NODEFAULT
   this.setfocus()
ELSE
   thisform.doNotClose = .F.
ENDIF

*** QueryUnload
IF thisform.doNotClose = .T.
  NODEFAULT
  RETURN
ENDIF

Regards,
Manni
 
For any validation, I still prefer the Valid event because it's more concrete and is always triggered whenever the textbox changes, and has built-in functionality to ensure you can't leave it until it's valid without needing any hacks.

However, if the initial value is critical and has the potential to not be valid right from the start, you still need to confirm it's valid before closing the form because LostFocus and Valid are only called when you enter the box.
 
I have just put this in the textbox QualPDEmissao, Valid event: (and nothing in the LostFocus event)
Code:
IF EMPTY(this.Value) OR this.Value>thisform.QualUDEmissao.Value
    this.BackColor = RGB(255, 128, 128)
    RETURN .F. && This stops the cursor from moving to the next field
ELSE
    this.BackColor = RGB(255, 255, 255) && Reset to default color if valid
    RETURN .T.
ENDIF

And it is working as I need, with your valuable help! :)
 
I still prefer the Valid event because it's more concrete and is always triggered whenever the textbox changes
True, but there must be any line of Code or comments. In case of a BINDEVENT(SrcObject, "Valid", DstObject, "UDF_Name") the event dont fire if the Valid-Method is empty.
 
For any validation, I still prefer the Valid event because it's more concrete and is always triggered whenever the textbox changes, and has built-in functionality to ensure you can't leave it until it's valid without needing any hacks.

However, if the initial value is critical and has the potential to not be valid right from the start, you still need to confirm it's valid before closing the form because LostFocus and Valid are only called when you enter the box.
Joe, I didn't know that the Valid event automatically leaves the focus in the textbox when you return .F. That's why I unnecessarily always used the LostFocus event in combination with NODEFAULT, which was recommended to me long ago in another forum.

Is there any way to suppress the wait window that appears after RETURN .F. in the valid event? I prefer to give a more detailed message in a messagebox instead.

Thanks,
Manni


EDIT: I just found the answer to my last question in Hackers Guide to VFP:
if SET NOTIFY is ON (not something we generally recommend), when a Valid returns .F., a wait window saying "Invalid Input" appears. If there's code in the control's ErrorMessage, that runs first, but then the "Invalid Input" window appears. To avoid this, either SET NOTIFY OFF or RETURN 0 rather than .F. from the Valid.

So RETURN 0 in the valid event suppresses the WAINT WINDOW "Invalid Input".
 
Last edited:
Valid is still the best place to validate something and its entire purpose is to allow the method to prevent the user from moving to the another control without first making sure it's an acceptable value. So in a nutshell Valid always fires before LostFocus because you can't lose focus until the control is considered valid.

That's also why they don't allow you to call SetFocus from the valid event. If you want to allow people to exit the control, it must always return a true value. Where it goes next can be handled in the default using the tab order, or by placing a SetFocus in the LostFocus events.

Technically, instead of returning false for an invalid entry you can use LostFocus or Valid to modify the value in a way that makes it valid. You'll still be requited return true, but you can use the event to change the control back to a default value, or prompt the user to select something else.

Keep in mind that whenever you write any code in any built-in event, it generally disables the default behavior, so if you want to do something different there are a few potential variations on if and how to handle the default behavior.

1. You can write code that happens INSTEAD of the default event by simply typing your code.

2. You can write code that happens BEFORE the default code, by calling DODEFAULT() at the end of your code to let the DEFAULT behavior happen AFTER YOUR code.

3. You can write code that happens AFTER the default code, by starting your code with DODEFAULT(), then YOUR code happens AFTER the DEFAULT.

4. You can also call DODEFAULT() anywhere in the middle and even make it conditional, by saying IF (something) to only call the default behavior when and (something) is true.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top