Why does OnKillFocus, and OnRetunPressed fire twice for textbox

Started by jmaeding, April 18, 2011, 01:08:31 PM

Previous topic - Next topic

jmaeding

I use those events to validate values, here is an example:
Code (autolisp) Select
;ELEVATION PRECISION TEXTBOX
(defun c:frmEditVA_txtElevPrec_OnKillFocus ()
  (frmEditVA_txtElevPrec_Validate)
)
(defun c:frmEditVA_txtElevPrec_OnReturnPressed ()
  (frmEditVA_txtElevPrec_Validate)
)
(defun frmEditVA_txtElevPrec_Validate ( / Value)
  (Setq Value (CT-REMOVE-CHARS (DCL_Control_GetProperty (vl-doc-ref 'CT-Civil10-B_frmEditVA_txtElevPrec) "Text")))
  (IF (= (CHECK_FOR_NUM Value) 0)
    (PROGN
      (PUT-GVAR "ELEVPREC" (ATOI Value) "CT-EDITVA-GVAR")
      (FIX-GVARS "CT-EDITVA-GVAR" (CT-EDITVA-GVAR-LIST))
      (PUT-CT-EDITVA-GVAR-INFILE)
      (frmEditVA_DoGrid)
    )
    (PROGN
      (ALERT "Precision was not valid")
      (DCL_Control_SetProperty (vl-doc-ref 'CT-Civil10-B_frmEditVA_txtElevPrec) "Text"
        (ITOA (GET-GVAR "ELEVPREC" "CT-EDITVA-GVAR"))
      )
    )
  )
)


Those two events fire twice every time.  Would not matter, but sometimes I give user feedback like the alert shown, and that shows twice.
I brought this up in the past, am not sure if its proper behavior though.
Note that OnReturnPressed should not fire at all IMO, if you click to another control, just OnKillFocus should fire.

jmaeding

after some testing, it seems my calls to update other text boxes are causing the firing.
I did not think changing another control's value was the same as lost focus though.
My other control has no events wired, so there is no interaction between them.

Its not making sense.

owenwengerd


jmaeding

am working on the example.  Cannot replicate the behavior yet.
I forgot to mention the dialog is modeless, that may have something to do with it.
Seems one things is clear, the onkillfocus is caused by an "enter" to the textbox.
Looks like focus is lost to the modeless dialog on an enter.

Still not sure why my real dialog is double dipping, I'll keep experimenting.

jmaeding

Here is an example.
Important notes:
1) Its modeless, and I don't want escape to close it, so flag TEST:OKTOCLOSE is set to deal with that.
2) When textbox1 loses focus, or enter is pressed, I want textbox2's value to change
3) When enter is pressed for textbox1, and the validate ran successfully (from the lostfocus event), I want its value to be selected, so user can type another value.  Pattern is type, enter, type, enter....

One thing I realised is it makes no sense to put the validate code in both events.  An enter always causes focus to be loast.  OnKillFocus is the place to put validate code.  So now I am saving the return of the validate function in a global var, and checking it in the retunpressed event to see if selection should be done.

I get four lostfocus events with this though.  Can I avoid this with better structure?

jmaeding

I think part of the problem, is OnKillFocus fires before OnReturnPressed.
If it was reverse, I could set a flag saying the cause of the lost focus was the return.

I know my (dcl_TextBox_SetSel TestEvents_Form1_TextBox1 0 -1) is causing the lost focus event, but am not sure why.
If SetSel gives focus back, what is causing it to lose focus after, thus causing the event to fire.
I would say SetSel should not be firing any events at all, because if anything, it is GIVING focus to the texbox1, not losing it.

jmaeding

ok, I fooled myself on two items.  An enter which fired OnReturnPressed, does not fire the OnKillFocus event.
It was my call to SetProperty "Text" on textbox2 that was doing it.
Also, my Alert code causes focus to be lost, what a mess I made of troubleshooting.
So I cannot take out the validate from OnReturnPressed, and my plight gets worse.

In .net, you could handle this by unwiring the events from the controls before the property update, then rewire after.
This is really tricky in ODCL, as updating other controls after a text edit is very common, and that would fire the same event (OnKillFocus) that you should put the code that updates the other controls.

The tricky part is telling what is the first time OnKillFocus is being called.  If I could do that, i could set a flag to just run the code once within the validate.  I don't mean to drag on about this, but text validation is a super common and important process, so a rock solid pattern approach is needed.

owenwengerd

I wonder if you couldn't wire and unwire the OnKillFocus event as you suggest. You could unwire it as soon as it fires, then wire it in OnEditChanged (or OnSetFocus maybe).