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 Mike Lewis 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

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
 
You have to add to 1: To stop the native behavior you also have to do a NODEFAULT.

In this problem, it's not that SetFocus doesn't work, it's that the default native behavior of the LostFocus event of any control is to set focus to the next control in tab order, which already has had its When event firing beforehand and respoinded to that with .t. - which is done by default even with no code in When events.

So that's the problem, actually. You can see so with eventtracking, the Setfocus does set focus back to itself, but that doesn't override the behavior of the LostFocus to eventually set focus to the next control. If I do eventtracking the event list lists the when,gotfocus of the textbox with the verification in Lostfocus, then has another gotfocus of that same textbox that is happening because if the SetFocus call, but then also the GotFocus of the next textbox or control in general. Becuase that was already decided by the focus change mechanism before the Lostfocus even got triggered. Learn event sequences. For focus changes you don't just have lostfocus of the previous control and gotfocus of the next control, you first have WHEN of the next control, then lostfocus of previous and gotfocus of next. The documentation of Setfocus tells you it does not work from When, Valid RangeLow and RangeHigh events (the latter of the Spinner control):
SetFocus Method
In Visual FoxPro 9.0, the SetFocus method is not supported in the When Event, Valid Event, RangeHigh Event and RangeLow Event events. However, you can include a RETURN Command with an object name (RETURN <ObjectName>) in these events to set the focus to another control. If a RETURN command with an object name is included, the focus is set to the control specified with <ObjectName>.

And the last part of it tells you what else to use; The RETURN mechanism, that's not limited to .T./.F., but also can be an object including THIS and a number, a jump in tab order by N, including 0 to stay.

Back on track of the NODEFAULT/DODEFAULT(): Likewise of only preventing Lostfocus to finally set focus to the next control despite your setfocus, you don't prevent the key press processing by putting code in Keypress onyl ba having code, you only suppress it when also explicitly doing NODEFAULT in your code. DODEFAULT() is not calling the native base behavior that's encoded in the VFP classes within C++ code of the runtime, at least not in every method of every class. The way default behavior of a class works is simply siad "always, unless you do NODEFAULT", so there is no need for DODEFAULT(), usualy. In case of Keypress it works, but when you do it on top of your own code, that would cause all keys to show double. as your code alone doesn't supress it. If you do both DODEFAULT and NODEFAULT you get normal behaviour by explicitly calling it and then supressing the usual run of it as last step. With that you could have This.Value change which is not including the nKeyCode of the keypress event, yet. But then, if you want to react to the value change when it already happened you could use the InteractiveChange event that happens after the Keypress has happened. Agin, learn event sequences.

Anyway, in this case the better solution is to use the Valid event, not the Lostfous. And RETURN 0 or RETURN This, Only use RETURN .F. when you also want the "Invalid Input" wait window or when you have SET NOTIFY OFF, I'd not consider it bad to have it off. I'd rather be cautious with SET SAFETY OFF, though.

Besides all that, the better way of validation is done not at the individual control level, just ignore the existance of the valid event, unless you have a pressing case, like not being able to store an invalid value back into the controlsource of a bound control. Also using buffering then can help to TABLEREVERT and have a mechanism that handles ESC for cancelling. Just as described in https://hackfox.github.io/section4/s4g117.html
 
Last edited:
Good
You have to add to 1: To stop the native behavior you also have to do a NODEFAULT.
Good point. I forgot to mention the option to NOT run the default at all.

I generally use a DODEFAULT() somewhere in my overrides, especially of my custom controls.

Sometimes I want my default code run first, sometimes last, and other times last. When using code like this on a custom control, leaving out the DODEFAULT() in an override will NOT run the default behavior.
 
When using code like this on a custom control, leaving out the DODEFAULT() in an override will NOT run the default behavior.
Put a textbox on a form, write code into the Keypress event. Anything, even something unrelated to the keypress. That doesn't override the default keypress behavior The default behavior will happen, also if you don't write DODEFAULT(). And if you write DODEFAULT(), every keypress event will cause two times the default behavior, i.e. writing "hello" the value will become "hheelloo". Try it. You don't override the default native behavior, any code only overrides the parent class code by not calling it with dodefault, but the inbuilt default behaviror is not overridden just by writing code.
 
Put a textbox on a form, write code into the Keypress event. Anything, even something unrelated to the keypress. That doesn't override the default keypress behavior The default behavior will happen, also if you don't write DODEFAULT(). And if you write DODEFAULT(), every keypress event will cause two times the default behavior, i.e. writing "hello" the value will become "hheelloo". Try it. You don't override the default native behavior, any code only overrides the parent class code by not calling it with dodefault, but the inbuilt default behaviror is not overridden just by writing code.
Yes. You are correct. I was thinking more about custom controls. I tend to have tons of my own classes and totally custom methods that I either enhance by pushing my DODEFAULT() somewhere at the top or bottom, in in some cases as I mentioned, conditionally depending on some condition.
 
Yes, in that case you need it, but your first class actually needs to avoid it. And most people (unfortunately) use the native controls, no own (sub)class. Then DODEFAULT can actually harm more oten than it helps.

In the LostFocus case only NODEFAULT would help, despite that controlling the focus in Valid is the much better solution. anyway, and pointed out by the SetFocus help text, actually. So seeing trouble with your SetFocus and therefore reading its help chapter could have given you that idea, too, SitesMasstec. You still need to pick it up, but it's there, mentioned, as I quoted it above.
 
Last edited:
Yes, in that case you need it, but your first class actually needs to avoid it. And most people (unfortunately) use the native controls, no own (sub)class. Then DODEFAULT can actually harm more oten than it helps.

In the LostFocus case only NODEFAULT would help, despite that controlling the focus in Valid is the much better solution. anyway, and pointed out by the SetFocus help text, actually. So seeing trouble with your SetFocus and therefore reading its help chapter could have given you that idea, too, SitesMasstec. You still need to pick it up, but it's there, mentioned, as I quoted it above.

I cringe whenever I look at some of my older forms and notice they still use native controls.

My standard protocol is to base all of my controls on a class I built as a standard PRG that defines every single native control with the same name but with my own prefix.

Everything else is a sub-class of that class, or a sub class of one of those sub-classes.
 
I like it, but did you ever encounter Error 1965 - "One of the members of this class is based on a nonvisual class, Cannot write .VCX file."

Code:
Local loForm as Form

Create Class aform as form of "theforms.vcx" nowait
=ASelObj(aForm,1)
loForm = aForm[1]
loForm.AddObject("_text1","_textbox")
loForm.SaveAsClass("otherforms.vcx","copyofaform","a visual form class with a nonvisual member") && fails, because that's not allowed.

Define Class _textbox as textbox
   Fontsize = 10
   Height = 25
EndDefine
save as a prg and run it to see that error.

VFP doesn't like when you add members to a visual class (a class stored in a VCX library file) that are a nonvisual class (a class based on the DEFINE CLASS command in a PRG). That's the reason for the ffc vcx library Home()+"\FFC\_BASE.VCX" and not a _BASE.PRG with all these definitions.
 
Last edited:

Part and Inventory Search

Sponsor

Back
Top