Recent

Author Topic: TDateTimePicker calls FormActivate every time the date is changed  (Read 1016 times)

JD

  • Hero Member
  • *****
  • Posts: 1837
TDateTimePicker calls FormActivate every time the date is changed
« on: September 22, 2021, 05:18:05 pm »
Hi there everyone,

I have noticed a strange occurence with the TDateTimePicker control and FormActivate.

Everytime one changes the date in TDateTimePicker, FormActivate is called. Is this normal behaviour?

How do I get around it because it is causing one of my applications to behave strangely?

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, DateTimePicker;
  9.  
  10. type
  11.   { TForm1 }
  12.   TForm1 = class(TForm)
  13.     DateTimePicker1: TDateTimePicker;
  14.     procedure FormActivate(Sender: TObject);
  15.   private
  16.  
  17.   public
  18.  
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. { TForm1 }
  29.  
  30. procedure TForm1.FormActivate(Sender: TObject);
  31. begin
  32.   //if Sender is TDateTimePicker then
  33.     ShowMessage('Form activate called!');
  34. end;
  35.  
  36. end.
  37.  


JD
Windows (10) - Lazarus 2.1/FPC 3.2 (svn 64160 built using fpcupdeluxe),
Linux Mint - Lazarus 2.1/FPC 3.2 (svn 64380 built using fpcupdeluxe),
Delphi

Indy 10.6 series; mORMot; Zeos 7.3; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

wp

  • Hero Member
  • *****
  • Posts: 8881
Re: TDateTimePicker calls FormActivate every time the date is changed
« Reply #1 on: September 22, 2021, 06:14:33 pm »
Everytime one changes the date in TDateTimePicker, FormActivate is called. Is this normal behaviour?
I think so. Because the dropdown calendar is in its own form which is shown non-modally. The same occurs for TDateEdit and TTimeEdit. Whenever a non-modal form is activated/deactivated the OnActivate and OnDeactivate events are fired. And this happens when these dropdowns are closed - now the parenting form becomes active again and fires the OnActivate event.

TCalcEdit and TDirectoryEdit do not show this behaviour - here the "dropdown" is a separate form, too, but it is a shown modally. When focus returns to the initial form after closing a modal form the OnActivate event does not fire.

Maybe the TColorPicker, TDateEdit and TTimeEdit can be rewritten to show the dropdowns modally (I have no idea about the implications) or to use custom controls rather than forms for their dropdowns - but all these require a major rework in these components.

You should reconsider the logic of your event handling. For example you can provide a boolean "ActivateCalled" status variable which you set to true the first time when the form gets activated and thus can prevent execution of the code in the OnActivate handler multiple times (https://wiki.freepascal.org/Execute_action_after_form_is_shown#OnActivate_event).
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

Zoran

  • Hero Member
  • *****
  • Posts: 1675
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: TDateTimePicker calls FormActivate every time the date is changed
« Reply #2 on: September 22, 2021, 06:17:57 pm »

Everytime one changes the date in TDateTimePicker, FormActivate is called. Is this normal behaviour?

You mean, when the drop-down calendar in DateTimePicker gets closed, the parent's form's OnActivate handler is called. Right?

It is a known problem, but not much can be done in TDatePicker to avoid it.
The problem is that the drop-down calendar, when shown, actually creates its own form and it steals the focus from DateTimePicker's parent form. When the calendar form is closed, the DateTimePicker's parent form gets the focus back. Then the activate event is triggered.

It was discussed once.

GetMem

  • Hero Member
  • *****
  • Posts: 3490
Re: TDateTimePicker calls FormActivate every time the date is changed
« Reply #3 on: September 22, 2021, 06:23:00 pm »
Hi JD,

Quote
I have noticed a strange occurence with the TDateTimePicker control and FormActivate.

Everytime one changes the date in TDateTimePicker, FormActivate is called. Is this normal behaviour?
Yes, it is normal behaviour. Take a look at the attached picture, it's clearly visible with Window detective, that TDateTimePicker has a separate window(Form).

Quote
How do I get around it because it is causing one of my applications to behave strangely?
You can use TScreen class to detect when the active form is a dropped down TDateTimePicker, then change the behaviour on form activate:
Code: Pascal  [Select][+][-]
  1. //...
  2.   TForm1 = class(TForm)
  3.     DateTimePicker1: TDateTimePicker;
  4.     procedure FormActivate(Sender: TObject);
  5.     procedure FormCreate(Sender: TObject);
  6.     procedure FormDestroy(Sender: TObject);
  7.   private
  8.      FCalendarIsActive: Boolean;
  9.      procedure OnAddForm(Sender: TObject; Form: TCustomForm);
  10.      procedure OnRemoveForm(Sender: TObject; Form: TCustomForm);
  11.   public
  12.  
  13.   end;
  14.  
  15. //...
  16.  
  17. procedure TForm1.FormCreate(Sender: TObject);
  18. begin
  19.   Screen.AddHandlerFormAdded(@OnAddForm);
  20.   Screen.AddHandlerRemoveForm(@OnRemoveForm);
  21. end;
  22.  
  23. procedure TForm1.FormDestroy(Sender: TObject);
  24. begin
  25.   Screen.RemoveHandlerFormAdded(@OnAddForm);
  26.   Screen.RemoveHandlerRemoveForm(@OnRemoveForm);
  27. end;
  28.  
  29. procedure TForm1.OnAddForm(Sender: TObject; Form: TCustomForm);
  30. begin
  31.   FCalendarIsActive := Form.ClassName = 'TDTCalendarForm';
  32. end;
  33.  
  34. procedure TForm1.OnRemoveForm(Sender: TObject; Form: TCustomForm);
  35. begin
  36.   FCalendarIsActive := False; //called after Form1 FormActivate
  37. end;
  38.  
  39. procedure TForm1.FormActivate(Sender: TObject);
  40. begin
  41.   if FCalendarIsActive then //called first
  42.   begin
  43.     ShowMessage('we closed the calendar');
  44.     Exit;
  45.   end
  46.   else
  47.   begin
  48.     // do other non calendar related processing
  49.   end;
  50. end;

PS: Tested on Windows 10, Lazarus Trunk, FPC 3.2.2. It should work on other widgetsets too.

 

TinyPortal © 2005-2018