{"id":238,"date":"2013-08-18T20:16:37","date_gmt":"2013-08-18T18:16:37","guid":{"rendered":"http:\/\/blog.kassebaum.eu\/?p=238"},"modified":"2013-08-19T16:31:06","modified_gmt":"2013-08-19T14:31:06","slug":"anonymous-timer-and-firemonkey","status":"publish","type":"post","link":"https:\/\/www.kassebaum.eu\/blog\/2013\/08\/18\/anonymous-timer-and-firemonkey\/","title":{"rendered":"Anonymous Timer and FireMonkey"},"content":{"rendered":"<p>I guess that everyone knows the good old timer and its OnTimer event. There is a timer for the VCL and for FireMonkey as well which are nearly similar.<br \/>\nIn both timers there is one thing missing: I would like to use an anonymous method for the OnTimer event instead of the old TNotifyEvent. The reason for this is that anonymous methods capture variables.<br \/>\nSince Delphi doesn&#8217;t offer this feature let&#8217;s implement it ourself.<br \/>\nLet&#8217;s start with a new unit and we will derive from the existing TTimer.<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"TTimer\" >unit FMX.Types.AnonymousTimer;\r\n\r\ninterface\r\n\r\nuses\r\n  System.SysUtils, System.Classes, FMX.Types;\r\n\r\ntype\r\n  TTimer = class(FMX.Types.TTimer)\r\n  ...\r\n  end;<\/pre>\n<p>I&#8217;m using the same classname for the new timer because then it is possible to use it without registering a new component. I will show this trick later.<br \/>\nFirst, let&#8217;s add a property for the anonymous method.<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"TTimer\" >...\r\n  TTimer = class(FMX.Types.TTimer)\r\n  strict private\r\n    FOnTimerA: TProc;\r\n    ...\r\n  public\r\n    property OnTimerA: TProc read FOnTimerA write FOnTimerA;\r\n  end;<\/pre>\n<p>After we added the new property we have to call it. That&#8217;s why I will override the DoOnTimer method.<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"TTimer\" >...\r\n  TTimer = class(FMX.Types.TTimer)\r\n  strict private\r\n    FOnTimerA: TProc;\r\n  strict protected\r\n    procedure DoOnTimer; override;\r\n  public\r\n    property OnTimerA: TProc read FOnTimerA write FOnTimerA;\r\n  end;\r\n\r\nimplementation\r\n\r\n{ TTimer }\r\n\r\nprocedure TTimer.DoOnTimer;\r\nbegin\r\n  if Assigned(FOnTimerA) then\r\n    FOnTimerA\r\n  else\r\n    inherited DoOnTimer;\r\nend;\r\n<\/pre>\n<p>Now, we have a small problem: Delphi only creates the underlying timer object of the operation system if the OnTimer event of a TTimer is assigned. You can see this in the unit FMX.Types.<\/p>\n<pre class=\"lang:delphi decode:true \" >unit FMX.Types;\r\n...\r\nprocedure TTimer.UpdateTimer;\r\nbegin\r\n  KillTimer;\r\n  if (FEnabled) and (FInterval &gt; 0) and \r\n    (([csDesigning, csLoading, csDestroying] * ComponentState = [])) and\r\n    Assigned(FOnTimer) then\r\n  begin\r\n    ...\r\n  end;\r\n  ...\r\nend;\r\n<\/pre>\n<p>That&#8217;s why we need a dummy OnTimer event.<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"TTimer\" >unit FMX.Types.AnonymousTimer;\r\n\r\ninterface\r\n\r\nuses\r\n  System.SysUtils, System.Classes, FMX.Types;\r\n\r\ntype\r\n  TTimer = class(FMX.Types.TTimer)\r\n  strict private\r\n    FOnTimerA: TProc;\r\n    procedure OnTimerDummy(Sender: TObject);\r\n  strict protected\r\n    procedure DoOnTimer; override;\r\n  public\r\n    constructor Create(AOwner: TComponent); override;\r\n    property OnTimerA: TProc read FOnTimerA write FOnTimerA;\r\n  end;\r\n\r\nimplementation\r\n\r\n{ TTimer }\r\n\r\nconstructor TTimer.Create(AOwner: TComponent);\r\nbegin\r\n  inherited Create(AOwner);\r\n  OnTimer := OnTimerDummy;\r\nend;\r\n\r\nprocedure TTimer.DoOnTimer;\r\nbegin\r\n  if Assigned(FOnTimerA) then\r\n    FOnTimerA\r\n  else\r\n    inherited DoOnTimer;\r\nend;\r\n\r\nprocedure TTimer.OnTimerDummy(Sender: TObject);\r\nbegin\r\n  \/\/This is only a dummy event so that the OnTimer event is assigned.\r\nend;\r\n\r\nend.\r\n<\/pre>\n<p>Okay, that&#8217;s it. Now we have a TTimer with an anonymous method. I guess we should use it then. \ud83d\ude42<\/p>\n<p>We simply create a form, put two labels and a normal timer on it. Then we add the unit FMX.Types.AnonymousTimer to the uses clause after the unit FMX.Types. The designer now creates a normal timer and we can set all the normal timer properties.<\/p>\n<p>At runtime the compiler replaces the normal timer with our new one because the last unit in the uses clause has the highest visibility. This trick only works because we added no published properties to our new timer component.<\/p>\n<pre class=\"lang:delphi decode:true \" >unit Unit1;\r\n\r\ninterface\r\n\r\nuses\r\n  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,\r\n  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,\r\n  FMX.StdCtrls, FMX.Types.AnonymousTimer;\r\n\r\ntype\r\n  TForm1 = class(TForm)\r\n    Label1: TLabel;\r\n    Timer1: TTimer;\r\n    Label2: TLabel;\r\n    procedure FormCreate(Sender: TObject);\r\n  end;\r\n\r\nvar\r\n  Form1: TForm1;\r\n\r\nimplementation\r\n\r\n{$R *.fmx}\r\n\r\nprocedure TForm1.FormCreate(Sender: TObject);\r\nvar\r\n  I: Integer;\r\nbegin\r\n  I := 0;\r\n  Timer1.OnTimerA := procedure\r\n  begin\r\n    Inc(I);\r\n    if I &gt; 100 then\r\n      I := 0;\r\n    Label1.Text := I.ToString;\r\n  end;\r\nend;\r\n\r\nend.\r\n<\/pre>\n<p>The result is a label which shows the expired seconds until 100.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I guess that everyone knows the good old timer and its OnTimer event. There is a timer for the VCL and for FireMonkey as well which are nearly similar. In both timers there is one thing missing: I would like &hellip; <a href=\"https:\/\/www.kassebaum.eu\/blog\/2013\/08\/18\/anonymous-timer-and-firemonkey\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,3],"tags":[5,28],"class_list":["post-238","post","type-post","status-publish","format-standard","hentry","category-firemonkey","category-tipsandtricks","tag-delphi","tag-firemonkey"],"_links":{"self":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts\/238","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/comments?post=238"}],"version-history":[{"count":17,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts\/238\/revisions"}],"predecessor-version":[{"id":255,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts\/238\/revisions\/255"}],"wp:attachment":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/media?parent=238"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/categories?post=238"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/tags?post=238"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}