Normally you can't set the focus to a control through the valid() or when() event of a method. Their behavior maintains compatibility with the original controls that were in earlier versions of foxpro. However, there are a few workarounds - here's one.
Enter 'Name' in Input 1 with the case as shown without the quotes and the focus will be set to Input 3. Any other value in Input 1 will set the focus to Input 2.
The 4th and 5th textboxes show the number of times the valid() and lostfocus() events fire every time you exit Input 1.
Notice the valid() events fires twice; so if there is critical code in there that should only be run once, you'll have to include a test for this VFP anomaly. That's why
bBeenHere is used. This will happen whether the 'do case' structure is in the valid() or lostfocus() events.
Also, the behaviour is the same if you exit Input 1 via mouse click, so... if you want to set the focus via a mouse click you'll have to test for mouse activity and bypass the .setfocus() line in lostfocus().
oForm = createobject("Form1"

oForm.show
read events
define class form1 as form
docreate = .t.
visible = .t.
height = 100
width = 525
autocenter = .t.
add object Text1 as textbox with;
visible = .t.,;
width = 100,;
top = 20,;
oTgtObj = null,;
bBeenHere = .f.
add object Text2 as textbox with;
visible = .t.,;
width = 100,;
left = 110,;
top = 20
add object Text3 as textbox with;
visible = .t.,;
width = 100,;
left = 213,;
top = 20
add object Text4 as textbox with;
visible = .t.,;
width = 100,;
left = 316,;
top = 20,;
value = 0
add object Text5 as textbox with;
visible = .t.,;
width = 100,;
left = 419,;
top = 20,;
value = 0
add object Label1 as label with;
autosize = .t.,;
visible = .t.,;
top = 3,;
left = 0,;
caption = "Input 1"
add object Label2 as label with;
autosize = .t.,;
visible = .t.,;
top = 3,;
left = 110,;
caption = "Input 2"
add object Label3 as label with;
autosize = .t.,;
visible = .t.,;
top = 3,;
left = 213,;
caption = "Input 3"
add object Label4 as label with;
autosize = .t.,;
visible = .t.,;
top = 3,;
left = 316,;
caption = "X's valid() fired"
add object Label5 as label with;
autosize = .t.,;
visible = .t.,;
top = 3,;
left = 419,;
caption = "X's lostfocus() fired"
procedure destroy
clear events
endproc
procedure Text1.valid
if !this.bBeenHere && Test if valid has fired already
do case && used case for expansion of tests
case allt(this.value) == "Name"
this.oTgtObj = thisform.text3
otherwise
this.oTgtObj = thisform.text2
endcase
this.bBeenHere = .t.
else
this.bBeenHere = .f.
endif
thisform.text4.value = thisform.text4.value + 1 && Bump the x's valid has fired
endproc
procedure Text1.lostfocus
thisform.text5.value = thisform.text5.value + 1 && Bump the x's lostfocus has fired
this.oTgtObj.setfocus()
endproc
enddefine
'We all must do the hard bits so when we get bit we know where to bite'
