Lazarus

Using the Lazarus IDE => Editor => Topic started by: greenmask on November 20, 2020, 11:05:45 pm

Title: Problem with DateTimePicker
Post by: greenmask on November 20, 2020, 11:05:45 pm
Hi! everyone, I've a problem with DateTimePicker, when I select date,  it's execute event Form OnActivate, if I have edit1.clear on event form OnActivate,  it's is executed, How can solution this? My Ide is versiĆ³n 2.0.10, thank for answer.
Title: Re: Problem with DateTimePicker
Post by: Eleazar on November 20, 2020, 11:45:21 pm
Hi Greenmask,
I think it is normal behavior of the TDateTimePicker component. The TDateTimePicker uses a customform to draw the calendar on. When it is closed a killfocus is executed and the focus is given back to the parent, in this case your form. So when this is activated again, you get the OnActivate. I don't see a quick solution to prevent this. Maybe someone else does?
Greetings, Leo
Title: Re: Problem with DateTimePicker
Post by: howardpc on November 20, 2020, 11:52:03 pm
Yes, the parent form's reactivation is built in to the date selection (which causes the control's window to close and the parent to regain focus, if possible).
Perhaps you could do your edit1.Clear in another form event such as OnShow?
Title: Re: Problem with DateTimePicker
Post by: greenmask on November 21, 2020, 12:22:20 am
The problem is that if I have some code in the onActivate event it will be executed again, in the embarcadero delphi ide I have no problem, I can change the date over and over again without any code that I have in onActivate being activated, without a doubt I don't like this behavior, it causes me a lot of trouble and wasted time. Return to Embarcadero IDE. Greetings.
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 21, 2020, 01:31:59 am
There is a quick and dirty workaround: in DateEdit.OnCloseUp set a form flag FSuspend to true and reset it in Form.OnActivate. For example:

Code: Pascal  [Select][+][-]
  1. procedure TfrmTouchMain.edDateCloseUp(Sender: TObject);
  2. begin
  3.   FSuspended := True;
  4. end;
  5.  
  6. procedure TfrmTouchMain.FormActivate(Sender: TObject);
  7. begin
  8.   if not FSuspended then
  9.     // activation code here
  10.   FSuspended := False;
  11. end;

But I don't think this is correct behaviour since no other control on a form would trigger OnActivate when it's contents are altered. I'd suggest to file a bug report.
Title: Re: Problem with DateTimePicker
Post by: greenmask on November 21, 2020, 03:10:15 am
Sieben: Thank you very much for the code, but what is Fsuspended, is a variable boolean?  I think that DateTimePicker has a bug, in embarcadero delphi I can use the datetimepicker without problem. Respectfully lazarus does not outperform delphi 7 much less recent versions, however where can I report the bug?
Title: Re: Problem with DateTimePicker
Post by: howardpc on November 21, 2020, 09:21:48 am
I agree with Sieben: no changing control should trigger its parent form's OnActivate.
The Delphi control is primarily designed for Windows, and can fully rely on WinAPI calls.

The Lazarus control has to be fully cross-platform, and has resorted to the hack of using an activation message in an attempt to manage automatic change of focus. While this 'works' it has the undesired side effect you encountered, and I think will ultimately be regarded as a poor design decision.

I've never used the Lazarus TDateTimePicker, and now I see how it is implemented, I doubt I ever will use it.
Title: Re: Problem with DateTimePicker
Post by: lucamar on November 21, 2020, 11:19:41 am
Sieben: Thank you very much for the code, but what is Fsuspended, is a variable boolean?

I'm not Sieben (obviously :)) but the normal way of implementing those kind of things is as a field of the form, so in the interface section of your form's unit you'd have something like:

Code: Pascal  [Select][+][-]
  1. type
  2.   TfrmTouchMain = class(TForm)
  3.      {controls, etc, here}
  4.   private
  5.     FSuspend: Boolean;
  6.   public
  7.     {other things here}
  8.   end;

One small gotcha of those workarounds is that you should make sure the fields start with a known value, so you have to add an OnCreate event handler and initialize them:

Code: Pascal  [Select][+][-]
  1. procedure TfrmTouchMain.FormCreate(Sender: TObject);
  2. begin
  3.   FSuspend := False;
  4.   {... other initializations, if any ...}
  5. end;
Title: Re: Problem with DateTimePicker
Post by: wp on November 21, 2020, 11:20:41 am
if I have edit1.clear on event form OnActivate,  it's is executed.
I agree that triggering OnActivate by the DateTimePicker should be avoided (although I am not sure whether this is possible). But what you are saying here indicates bad design, don't clear an Edit control in OnActivate: When you open a second form OnActivate will be called, too, and erase your edit. The same will happen when your for contains another nonmodal form which you activate and you return to the starting form. Put initialization code into OnCreate, or call it from the routine which activated this form. Don't say "This does not apply to me" - who knows what you are doing in a year when you forgot all the details of this project?
Title: Re: Problem with DateTimePicker
Post by: lucamar on November 21, 2020, 11:39:21 am
Put initialization code into OnCreate, [...]

One small problem with that approach is that at the time OnCreate is called not all controls are yet initialized so one has to defer further initializations (for example filling a TListBox) to OnActivate. For one time initializations one can add a boolean field called, say, DoneActivate or, if that's all the OnActivate handler does, simply start it with:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);
  2. begin
  3.   OnActivate := Nil;
  4.   {... rest of deferred initializations ...}
  5. end;

That will prevent it being called more than once in the same run.
Title: Re: Problem with DateTimePicker
Post by: wp on November 21, 2020, 11:45:36 am
Agreed. I only wanted to emphasize that OnActivate can occur at any time, and the coder must be aware of that. When a program behaves incorrectly due to OnActivate being called this is not necessarily due to a bug of TDateTimePicker.
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 21, 2020, 12:56:03 pm
Quote from: lucamar
One small gotcha of those workarounds is that you should make sure the fields start with a known value, so you have to add an OnCreate event handler and initialize them:
In Delphi one could rely on any class vars to be initialized with zero, so explicitely initializing strings to '', integers to 0 or Booleans to false wasn't really necessary. Different with Lazarus...?
Title: Re: Problem with DateTimePicker
Post by: lucamar on November 21, 2020, 01:22:20 pm
Quote from: lucamar
One small gotcha of those workarounds is that you should make sure the fields start with a known value, so you have to add an OnCreate event handler and initialize them:
In Delphi one could rely on any class vars to be initialized with zero, so explicitely initializing strings to '', integers to 0 or Booleans to false wasn't really necessary. Different with Lazarus...?

Yes, IIRC simple-type fields are initialized to its defaults, but it's nevertheless a good rule of thumb to make a explicit initialization. That way you can be absolutely sure of what each contains and, perhaps more important, you know exactly where to change that initial value if the need arises later on.

It may sound a little paranoid but, hey, even paranoids can have real enemies ;)
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 21, 2020, 01:24:22 pm
Would you please provide a minimal application which produces the bug?

I am the author and maintainer of TDateTimePicker and I would like to solve all bugs from the component.

However, I have to admit I do not understand what this is about. :-[
I am not a native English speaker.
I cannot see what has DateTimePicker to do with clearing of an edit box.

You also didn't provide all information about your system.
Which OS, widgetset.

So, test application please!
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 21, 2020, 01:36:46 pm
The 'bug' is simply that OnActivate of the parent form will be called after selecting a value from the calendar in dtkDate mode. This is at least unusual for a control that just changes value. Gtk2 here.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 21, 2020, 01:53:28 pm
I see, I get it now. The closing of DateTimePicker's calendar form triggers the activation of DateTimePicker's parent form.

I'll try to see if I can do something. I would like to solve it, but I am not sure if it is possible. Perhaps some workaround can be found...

It seems that other custom controls which show drop-down form also suffer from this (I have just tested DateEdit -- same problem).

Please report it in bugtracker (http://bugs.freepascal.org/view_all_bug_page.php?project_id=1).
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 21, 2020, 02:11:16 pm
Please report it in bugtracker (http://bugs.freepascal.org/view_all_bug_page.php?project_id=1).

I see you already did (Bug 38108). (https://bugs.freepascal.org/view.php?id=38108)
Thank you for reporting!
Title: Re: Problem with DateTimePicker
Post by: greenmask on November 21, 2020, 03:39:01 pm
A few hours ago I reported the bug in LazarusBugTracker, a developer agrees with the DateTimePicker problem, although they also emphasize that it is bad design to use the OnActivate event.

I agree with what was said about a bad design, however perhaps because of that bad practice of including initialization code in the OnActivate I saw the problem.

1. In a Form1, you put an Edit1, Edit2, DateTimePicker1.
2. In the onActivate event of the Form you write an Edit1.clear; Edit2.clear;
3. You run.
4. You enter something in edit1 and edit2.
5. You select any date.

With these steps you can see that the Edits (Edit1,edit2) are immediately cleaned up because onActivate was activated. Selecting a date in the DateTimePicker calls the onActivate and executes some code that is there.

The fact that using the OnActivate is bad design practice does not mean that the DateTimePicker should activate the OnActivate of the Form.

Greetings to all and thanks for responding. Blessings.

OS Linux Mint 19.1 Tessa 64 bits - Lazarus 2.0.10 - fpc 3.2.0
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 21, 2020, 04:42:53 pm
The fact that using the OnActivate is bad design practice does not mean that the DateTimePicker should activate the OnActivate of the Form.


I fully agree with that, as I said in that report.

As I also said, the only clean solution would be to prevent stealing of focus from the parent form in the first place.

However, I doubt that it is possible. The built-in controls, like Combo boxes and pop-up menus can do it, but I don't think that a custom control can show some kind of a pop-up window other way than creating a separate form, which then the application will treat just like that - a separate form. So, when the pop-up form receives focus, the original parent form of the main control loses focus - this will trigger OnDeactivate event - and when the focus is returned to the main control, its parent form gets focus again - this will trigger OnActivate.

I would like some workaround, but the fact that the other custom controls which also show their own pop-up forms non-modally have the same problem doesn't look promising...
Title: Re: Problem with DateTimePicker
Post by: wp on November 21, 2020, 04:51:16 pm
Instead of adding the popup calendar to a form, can't you add it to a panel? There could be code to hide (destroy?) the panel when the user clicks on a calendar date, tabs out of the calendar, presses ENTER. I do see a problem, though, when the user clicks outside the calendar or even outside the parenting form because in this case the click events will not be passed to the calendar.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 21, 2020, 06:46:02 pm
Instead of adding the popup calendar to a form, can't you add it to a panel? There could be code to hide (destroy?) the panel when the user clicks on a calendar date, tabs out of the calendar, presses ENTER. I do see a problem, though, when the user clicks outside the calendar or even outside the parenting form because in this case the click events will not be passed to the calendar.

No, sorry, I disagree with that idea.

Another (less aggressive) "solution" is to show the calendar modally (see bellow*), but I would disagree with that too.

I think that it would be much worse than, if nothing else can be done, just document that behaviour as a "non-solvable" bug (something like this (https://wiki.freepascal.org/Lazarus_known_issues_(things_that_will_never_be_fixed))).
Something like -- Be aware that form's OnDeactivate and OnActivate events will fire each time the calendar is dropped down and closed.

Please notice that other custom controls which show pop-up window non-modally suffer from this problem too (for example TDateEdit).

(*) Custom controls that show pop-up window modally do not trigger OnDeactivate and OnActivate (for example TCalcEdit)!


Title: Re: Problem with DateTimePicker
Post by: Sieben on November 21, 2020, 08:04:05 pm
Quote from: Zoran
No, sorry, I disagree with that idea.

For any particular reason...? What about storing and restoring the owner form's event handler when switching focus? Although I feel I don't know enough of the caveats of the underlying widgetsets etc to judge if this would be a way to go or not.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 21, 2020, 09:06:42 pm
Quote from: Zoran
No, sorry, I disagree with that idea.

For any particular reason...?

The panel? In my opinion, with this so different approach, it won't be DateTimePicker anymore.
There are many obstacles with this; first -- where and how to position it on the form?

This can be a new control. Fill free to create yet another date/time editor.
Well, it can have its place, some could prefer it to currently existing alternatives (TDateTimePicker, TDateEdit, TTimeEdit -- all with pop-up form approach). I would not.

But come on, if the reason for taking this approach is just this problem with focus, then no; I really can't think it's worth it.

What about storing and restoring the owner form's event handler when switching focus? Although I feel I don't know enough of the caveats of the underlying widgetsets etc to judge if this would be a way to go or not.

Of course, that is the idea, well, sort of...
I am experimenting with hooking parent's form WndProc, but... the results don't look promising for now -- in short, it looks like deactivate part might be solved, but activating not, there it seems that LM_ACTIVATE doesn't seem useful -- it is sent too late (depending on how the calendar gets closed, it can be before of after deactivate of calendar form). LM_SETFOCUS is more promising, it is sent when calendar is still active, but there also I cannot see a straightforward solution -- I need to be sure when it is called and remember it somewhere (provided the calendar form is active); but then a reliable place to restore old WndProc is needed. The order and the appearance of these messages doesn't look very reliable.
Anyway, it needs a lot of testing. And in all main widgetsets of course. Plus I cannot test on Mac.

In short -- don't expect much.
As far as I can see -- the "solution" will probably be just documenting this.
Title: Re: Problem with DateTimePicker
Post by: lucamar on November 21, 2020, 09:16:27 pm
Quote from: Zoran
No, sorry, I disagree with that idea.
For any particular reason...?

Here is a particular reason: if, like in most even semi-serious apps, you have a carefuly laid out form using anchors, control alignment, etc. having a panel pop-up in there has the extremely likely potential of disrupting everything  until it's again closed (and might not be restored even then). You need something that is almost completey outside the form (in this respect), and that's basically another, overlaid form.

It's not easy to deal with this problem.
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 21, 2020, 09:46:19 pm
Thank you both for explanations, I was just curious re the TPanel approach.

Quote from: Zoran
Feel free to create yet another date/time editor.

Oh no, I really like TDateTimePicker, and definitely prefer it to TDateEdit/TTimeEdit.

Quote
As far as I can see -- the "solution" will probably be just documenting this.

Fine with me. And there always is the workaround with the form flag laid out earlier in this thread.

Just another short question while you're here: how about adding Alignment property...?
Title: Re: Problem with DateTimePicker
Post by: Eleazar on November 21, 2020, 11:42:03 pm
Oh no, I really like TDateTimePicker, and definitely prefer it to TDateEdit/TTimeEdit.
Me too! I like the TDateTimePicker, thanks Zoran!
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 22, 2020, 12:03:27 am
Just another short question while you're here: how about adding Alignment property...?

Just to be sure -- You mean text alignment (which will override BidiMode, like CalAlignment overrides BidiMode)?
Currently, text alignment is controlled by BidiMode only (try it, but to see it, first set AutoSize to false and make the control wider).

I could add it, but as I see now how it is implemented in TLabel and TEdit, the behaviour is not consistent:
TLabel:
when BidiMode = bdRightToLeft, then everything is contra - when Alignment = taLeftToRight then the text is aligned to right side of the control and when taRightToLeft then to the right side
TEdit:
when BidiMode = bdRightToLeft, the text is aligned to right side, with both taLeftToRight and taRightToLeft.

In both these controls, when Alignment = taCenter, then BidiMode is ignored (as expected).

And in both controls, when BidiMode is bdRightToLeftNoAligned or bdRightToLeftReadingOnly, then they behave like bdLeftToRight. I don't understand what these are for.

I'd say, TEdit behaviour is probably a bug. However, I'm not satisfied with the way TLabel behaves either.
I would rather have taLeading and taTrailing added to this enumeration, which would behave like TLabel behaves with taLeftToRight and taRightToLeft respectively (they would follow BidiMode). Then, taLeftToRight and taRightToLeft would override BidiMode behaviour. And taLeading would be the default.

I could add a new enumeration in DateTimePicker for this Alignment property... However, I don't like not to follow the defaults...

Delphi's control (http://docwiki.embarcadero.com/Libraries/en/Vcl.ComCtrls.TDateTimePicker_Properties) does not have this property either.
But we are better than Delphi, of course (except for small inconvenience with focus ;) ).
I don't know; Is text alignment really needed?
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 22, 2020, 12:08:35 am
, but as I see now how it is implemented in TLabel and TEdit, the behaviour is not consistent:

I reported it: bug 38112 (https://bugs.freepascal.org/view.php?id=38112)
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 22, 2020, 02:58:14 pm
Quote from: Zoran
Just to be sure -- You mean text alignment ...

Yes, taLeftJustify, taRightJustify and taCenter. I have to admit that I never played around with combinations of Alignment and BiDiMode - but behaviour of TEdit is in fact peculiar.

Quote
I don't know; Is text alignment really needed?

Needed? No. I just thought taCenter would be nice to have, that's all.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 22, 2020, 11:36:57 pm
Quote from: Zoran
Just to be sure -- You mean text alignment ...

Yes, taLeftJustify, taRightJustify and taCenter. I have to admit that I never played around with combinations of Alignment and BiDiMode - but behaviour of TEdit is in fact peculiar.

Quote
I don't know; Is text alignment really needed?

Needed? No. I just thought taCenter would be nice to have, that's all.

Okay. Alignment property added in rev. 64155. Behaves like TLabel.
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 23, 2020, 09:45:49 pm
Very kind, thank you very much! Quite useful when you don't want to use AutoSize to eg match sizes of other controls and still have a decent look. How about DirectInput now...?  ;)

Btw is it possible to move this to a more appropriate place, eg 'Packages and Libraries'?
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 23, 2020, 10:47:32 pm
What is DirectInput?
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 23, 2020, 11:22:29 pm
Do you really...? DirectInput is a property used for example with TFileEdit or TDirectoryEdit to prevent the user from directly entering text into the edit portion of the control but to force him to use the buttons and the dialogs behind them. In case of TDateTimePicker the calendar controls, the UpDowns or the wheel. Defaults to True (direct input allowed) but can be set to False. Not really 'needed' as well...
Title: Re: Problem with DateTimePicker
Post by: Gald on November 23, 2020, 11:25:06 pm
Hi Zoran!

Is it possible to set the text a little bit away from the border? It's too close with the left side, the numbers are quite sharing the same pixels as the left border.

Example:

_________________
|23/11/2020      | v |
------------------------

_________________
| 23/11/2020     | v |
------------------------

Note that this is not related to text align direction but the spacing.
Title: Re: Problem with DateTimePicker
Post by: Gald on November 23, 2020, 11:42:03 pm
_____________
|23/11/2020      | v |
------------------------

_________________
| 23/11/2020     | v |
------------------------

Actually, forget it.
This should be common to all controls.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 24, 2020, 12:12:45 am
Do you really...? DirectInput is a property used for example with TFileEdit or TDirectoryEdit to prevent the user from directly entering text into the edit portion of the control but to force him to use the buttons and the dialogs behind them. In case of TDateTimePicker the calendar controls, the UpDowns or the wheel. Defaults to True (direct input allowed) but can be set to False. Not really 'needed' as well...

I see.
For that, you can use CalendarDialog (on Dialogs tab of control palette), together with a button and a read-only edit box (or just a label, or even a read-only DateTimePicker).
EDIT: better answer added later (https://forum.lazarus.freepascal.org/index.php/topic,52223.msg385424.html#msg385424).

So, yes, not really needed.
And too many not really useful properties do not bring quality.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 24, 2020, 12:18:38 am
_____________
|23/11/2020      | v |
------------------------

_________________
| 23/11/2020     | v |
------------------------

Actually, forget it.
This should be common to all controls.

Try setting BorderSpacing.InnerBorder property to value greater than zero.
Title: Re: Problem with DateTimePicker
Post by: Gald on November 24, 2020, 01:10:04 am
Try setting BorderSpacing.InnerBorder property to value greater than zero.

Thanks, it works.
Unfortunately, other controls don't follow the same rules.
There is no pattern about desing native controls?
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 25, 2020, 01:11:38 pm
Try setting BorderSpacing.InnerBorder property to value greater than zero.

Thanks, it works.
Unfortunately, other controls don't follow the same rules.
There is no pattern about desing native controls?

Native controls are implemented in widgetsets. Sometimes, some behaviour cannot be implemented in LCL, because the underlying widget does not behave that way.
Title: Re: Problem with DateTimePicker
Post by: Zoran on November 28, 2020, 12:38:42 pm
Do you really...? DirectInput is a property used for example with TFileEdit or TDirectoryEdit to prevent the user from directly entering text into the edit portion of the control but to force him to use the buttons and the dialogs behind them. In case of TDateTimePicker the calendar controls, the UpDowns or the wheel. Defaults to True (direct input allowed) but can be set to False. Not really 'needed' as well...


Actually, this behaviour can be achieved by setting something like this in OnKeyDown event:
Code: Pascal  [Select][+][-]
  1. uses
  2.   ...
  3.   LCLType, // needed for virtual key constants.
  4.   ...
  5.  
  6. procedure TForm1.DateTimePicker1KeyDown(Sender: TObject; var Key: Word;
  7.   Shift: TShiftState);
  8. begin
  9.   if Key in [
  10.     VK_0..VK_9, VK_NUMPAD0..VK_NUMPAD9
  11.     , VK_A, VK_P
  12.     // comment out the following line if you want to allow up and down arrow keys to change the date:
  13.     , VK_DOWN, VK_UP
  14.   ]
  15.   then
  16.     Key := 0;
  17. end;
  18.  

or you can use OnKeyPress instead, but only if you are not interested in suppressing up and down arrow keys (they cannot be caught by OnKeyPress), like this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.DateTimePicker1KeyPress(Sender: TObject; var Key: char);
  2. begin
  3.   if Key in ['0'..'9', 'A', 'P'] then
  4.     Key := #0;
  5. end;
  6.  

Is that what you would get with DirectInput?
Title: Re: Problem with DateTimePicker
Post by: Sieben on November 28, 2020, 09:48:16 pm
Yes, the latter one leaves it with the exact behaviour I had in mind. And it sure is easy enough to spare an extra property.
Thanks once more!  :)
TinyPortal © 2005-2018