Author Topic: Recursion ??  (Read 508 times)

J-G

  • Hero Member
  • *****
  • Posts: 1287
Recursion ??
« on: August 27, 2026, 08:33:43 pm »
Moving on from allocating data between forms, I now have what I might think of as 'Recursion'.  Having completed the entry of data into a field (in this case a 'Date') I use the OnEditingDone Event to
firstly :  validate that the input really is a proper date - allowing for '/' or '-' separators or even Text entry such as '27th Aug 2026' -  
secondly : convert raw date (26/8/26 say) to text '27th Aug 2026' and show that as the TEdit.Caption.

That all works as expected but in Debug mode I find that when I click on the next field to be edited, the 'OnEditingDone' is called again.  ????

I probably wouldn't notice at normal run-time except that it doesn't retain the entered data (string) so bilks at being given '' to evaluate as a number.  I might have trapped it by adding a Boolean Flag set true after the first test and checked before it does that (first test).  Can anyone suggest a reason - or preferably a better means by which such action can be eliminated without the 'Flag'?

Whether it will help I don't know, but here is the full Procedure :
Code: Pascal  [Select][+][-]
  1. procedure TFPerson.DoBEditingDone(Sender: TObject);
  2. Var
  3.   DS      : ShortString;
  4.   Db,Dd : Date;
  5.   Age     : TAge;
  6.   p        : byte;
  7. begin
  8.   If Done then Exit;
  9.   ErrorLab.Hide;
  10.   Done := True;
  11.   DS := DoB.Caption;
  12.   if Length(DS)<5 then
  13.     begin
  14.       Message := 'Cannot work with input as short as "'+DS+'"';
  15.       ErrorLab.Show;
  16.       Exit;
  17.     end;
  18.   p := Pos('/',DS);
  19.   if p=0 then
  20.     p:=Pos('-',DS);
  21.   if p=0 then
  22.     begin
  23.       DSToDt(DS,Db);
  24.       If Not DateGood then
  25.         begin
  26.           ErrorLab.Caption:=Message;
  27.           ErrorLab.Show;
  28.           Exit;
  29.         end;
  30.     end
  31.   else
  32.     begin
  33.       DS := DoB.Caption;
  34.       Person.DoBirth := DateFromText(DS);
  35.       Db := Person.DoBirth;
  36.       StringDate(Db,False,True,False);
  37.       DoB.Caption:=DateString;
  38.     end;
  39.   Dd := Person.DoDeath;
  40.   If Dd.d=0 then
  41.     Dd := Today;
  42.   Calc_Age(Db,Dd,Age);
  43.   Person.Age.Years:=Age.Years;
  44.   Person.Age.Days:=Age.Days;
  45.   FPerson.Age_Years.Caption:=IntToStr(Age.Years);
  46.   FPerson.Age_Days.Caption:=IntToStr(Age.Days);
  47.   DoB.SelLength:=0;
  48.   Self.SelectNext(ActiveControl, True, True);
  49. end;
  50.  
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

jamie

  • Hero Member
  • *****
  • Posts: 7938
Re: Recursion ??
« Reply #1 on: August 27, 2026, 11:43:51 pm »
I don't know which edit control you are using however, there should be a "MODIFIED" property you can use that indicates changes made to the edit field and that can be queried in the event, just remember to clear it when don't

Jamie
The only true wisdom is knowing you know nothing

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #2 on: August 28, 2026, 12:14:16 am »
Thanks for the hint @Jamie  but the only property begining with 'M' that I can see on a TEdit is MaxLength.

I suspect that I could store the state of the TEdit.Caption during an OnEnter event and compare that with the value at the start of the OnEditingDone Event but that seems just as inefficient as the 'If Done' option.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

jamie

  • Hero Member
  • *****
  • Posts: 7938
Re: Recursion ??
« Reply #3 on: August 28, 2026, 12:38:22 am »
The property is there. :o

TEdit.Modified {R/W}

and gets set when changes are made in the text.

Jamie
The only true wisdom is knowing you know nothing

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #4 on: August 28, 2026, 01:01:19 am »
Ah  -  I was looking at the Object Inspector 'property'  Now I see that you are referring the the list of options available after the dot operator.

You are correct of course and I can test for that rather than set a 'Done' flag - I'll need a little time to fully evaluate the option.


FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

cdbc

  • Hero Member
  • *****
  • Posts: 2944
    • http://www.cdbc.dk
Re: Recursion ??
« Reply #5 on: August 28, 2026, 01:26:32 am »
Hi
Let me help you out there:
Code: Pascal  [Select][+][-]
  1. procedure TFPerson.DoBEditingDone(Sender: TObject);
  2. Var
  3.   DS      : ShortString;
  4.   Db,Dd : Date;
  5.   Age     : TAge;
  6.   p        : byte;
  7. begin
  8.   If not DoB.Modified then Exit; ///<-
  9.   ErrorLab.Hide;
  10.   DoB.Modified := False; ///<-
  11.   DS := DoB.Caption;
  12.   if Length(DS)<5 then
  13.     begin
  14.       Message := 'Cannot work with input as short as "'+DS+'"';
  15.       ErrorLab.Show;
  16.       Exit;
  17.     end;
  18.   p := Pos('/',DS);
  19.   if p=0 then
  20.     p:=Pos('-',DS);
  21.   if p=0 then
  22.     begin
  23.       DSToDt(DS,Db);
  24.       If Not DateGood then
  25.         begin
  26.           ErrorLab.Caption:=Message;
  27.           ErrorLab.Show;
  28.           Exit;
  29.         end;
  30.     end
  31.   else
  32.     begin
  33.       DS := DoB.Caption;
  34.       Person.DoBirth := DateFromText(DS);
  35.       Db := Person.DoBirth;
  36.       StringDate(Db,False,True,False);
  37.       DoB.Caption:=DateString;
  38.     end;
  39.   Dd := Person.DoDeath;
  40.   If Dd.d=0 then
  41.     Dd := Today;
  42.   Calc_Age(Db,Dd,Age);
  43.   Person.Age.Years:=Age.Years;
  44.   Person.Age.Days:=Age.Days;
  45.   FPerson.Age_Years.Caption:=IntToStr(Age.Years);
  46.   FPerson.Age_Days.Caption:=IntToStr(Age.Days);
  47.   DoB.SelLength:=0;
  48.   Self.SelectNext(ActiveControl, True, True);
  49. end;
  50.  
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #6 on: August 28, 2026, 10:03:23 am »
Hi Benny  -  It was quite late last night when I read @Jamie's post but I did just test that 'Modified' was available  ;)

Looking at your suggestion, I don't see any benefit over the [Done] Boolean one. Maybe you (or someone) could enlighten me?

I also find the 'negation' (If Not ...) less 'readable' than a simple 'If'.

I would rather try to discover WHY the OnEditingDone Event is called twice rather than simply trap the second call.
« Last Edit: August 28, 2026, 10:05:45 am by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Zvoni

  • Hero Member
  • *****
  • Posts: 3527
Re: Recursion ??
« Reply #7 on: August 28, 2026, 10:35:18 am »
*snip*
That all works as expected but in Debug mode I find that when I click on the next field to be edited, the 'OnEditingDone' is called again.  ????
*snip*

*sigh*

https://lazarus-ccr.sourceforge.io/docs/lcl/controls/tcontrol.oneditingdone.html

Quote
The user has finished editing the value for the control, and the resulting text can be validated. It is called (when assigned) from the EditingDone method, which occurs when focus changes to another control.

Nevermind why not just use a TDateEdit ("Misc"-Controls) or DatePicker instead of allowing User to enter "Prose", which has to be validated
« Last Edit: August 28, 2026, 11:18:06 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #8 on: August 28, 2026, 11:22:36 am »
So - - - -   @Zvoni, you are saying that the behaviour is exactly as expected (and documented)  -  and pressing [Enter] (Return) does NOT signal that Editing is Done ?

My feeble brain tells me that when I hit [Return] and I see (in Debug mode) that the OnEditingDone Event IS activated that indicated otherwise.  I can now also appreciate that changing the Focus to another field would also call OnEditingDone perfectly reasonably. 

I suspect that OnEditingDone is not the best Event to use in this case so it may well be better to use OnKeyUp and trap for Key = #13. (or VK_RETURN)

Can you (or anyone) see any negative impact on that option ? 
« Last Edit: August 28, 2026, 11:38:21 am by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Zvoni

  • Hero Member
  • *****
  • Posts: 3527
Re: Recursion ??
« Reply #9 on: August 28, 2026, 11:34:47 am »
So - - - -   @Zvoni, you are saying that the behaviour is exactly as expected (and documented)  -  and pressing [Enter] (Return) does NOT signal that Editing is Done ?

My feeble brain tells me that when I hit [Return] and I see (in Debug mode) that the OnEditingDone Event IS activated that indicated otherwise.  I can now also appreciate that changing the Focus to another field would also call OnEditingDone perfectly reasonably. 

I suspect that OnEditingDone is not the best Event to use in this case so it may well be better to use OnKeyUp and trap for Key = #13.

Can you (or anyone) see any negative impact on that option ?

as a first: I would never use Enter/Return to trigger an OnEditingDone or any other Event specific to a Data-Entry-control.
The simple reason is, that i usually have a Button, which i declare as "Default" for the Form (e.g. "I'm done. Save it to Database" or similar).

Next: the proposed Way with the "Modified"-Property would actually be the preferable way.
Though what i could see:
You're setting "Done"/"Modified" at the Beginning of your Code!!! Somewhere around Line 3 of your Procedure
But later on you do a "DoB.Caption:=something" --> You're changing the Control again!

"Modified:=False" should be the last instruction before exiting the Function.

You hit Enter/Return
Your validation-Code in OnEditingDone executes
First Line checks if not Modified then Exit --> Since you actually modified the Control, this returns True, and code continues
As the last instruction you set Modified to False
You jump to the next control (which you actually do from Code!!!!)
OnEditingDone gets triggered again, but breaks out in the first line, since Modified is False
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #10 on: August 28, 2026, 11:59:39 am »
Thanks  @Zvoni - a very thorough disertation on the issue - eminently understandable.

In this particular case the Field is a DATE and since I want to allow a 'free-form' entry, the value of the entered data must be checked for validity. It would be cumbersome to have a [Finished editing Date] button for each Date field (there are two) and it is natural to end data-entry with a [Return].

Of course there is (will be  ;D) a [Save] button which will write the entire data record to the Database.

As far as "You jump to the next control (which you actually do from Code!!!!)" which seems to attract your ire  :D   -  I added that in a futile attempt to get around the problem. It may well be worthwhile anyway though, but I have yet to determine how to go back to first (or previous) [Tab]
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Zvoni

  • Hero Member
  • *****
  • Posts: 3527
Re: Recursion ??
« Reply #11 on: August 28, 2026, 12:34:34 pm »
*snip*
As far as "You jump to the next control (which you actually do from Code!!!!)" which seems to attract your ire  :D   -  I added that in a futile attempt to get around the problem. It may well be worthwhile anyway though, but I have yet to determine how to go back to first (or previous) [Tab]
I know what you mean, and i've struggled with that myself.

I've found an easy workaround (at least easy for me):
I create  an Array of the Controls that i'm interested in.
Next: I give those Controls the Index for its Tag-Property

In your case it would be something along the lines (Aircode)
Code: Pascal  [Select][+][-]
  1. Var
  2.   MyDateEdits:Array[0..1] Of TEdit;
  3.  
  4. //In FormCreate of the Form
  5. Begin
  6.   DateEdit1.Tag:=0;  //Same As Array-Index
  7.   DateEdit2.Tag:=1;
  8.  
  9.   MyDateEdits[0]:=DateEdit1;  //First DateEdit
  10.   MyDateEdits[1]:=DateEdit2; //Second DateEdit
  11. End;
  12.  
  13. //In the OnEditingDone
  14. Begin
  15. //blablablablabla
  16.  
  17.  
  18.    //Sender ships the Control which triggered this Event
  19.   If TControl(Sender).Tag=0 Then   //The left TEdit has Focus
  20.     MyDateEdits[1].SetFocus           //Move Focus to right TEdit
  21.   Else                                           //The right TEdit has Focus
  22.     MyDateEdits[0].SetFocus;         //Move Focus to left TEdit
  23.  
  24. End;

Pretty sure could be simplified even more, but that's my quick and dirty hack
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #12 on: August 28, 2026, 12:57:39 pm »
That's food for thought @Zvoni  -  for now I've deleted the Self.SelectNext(); at the end of each OnEditingDone and I've changed to OnKeyUp for the Dates.

Looks OK for now (no 'Recursion')  but there are still a lot of checks to do - not least of which is testing for 'Death' before 'Birth'  🤣

In the interests of 'Free form' Editing and logical use of keyboard data entry, the setting of 'Next' field may well involve checking for the [Arrow] Keys being pressed.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

creaothceann

  • Sr. Member
  • ****
  • Posts: 448
Re: Recursion ??
« Reply #13 on: August 28, 2026, 11:29:15 pm »
Why not the tab key? Just make sure each control's tab order is configured correctly.

J-G

  • Hero Member
  • *****
  • Posts: 1287
Re: Recursion ??
« Reply #14 on: August 29, 2026, 01:30:45 am »
Why not the tab key? Just make sure each control's tab order is configured correctly.
The [Tab]s are all set consequtively and I am aware of the option to [Shift][Tab] which reverses the direction but in the interests of 'flexability', trapping the Arrow Keys is a distinct possibility.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

 

TinyPortal © 2005-2018