Anonymous Timer and FireMonkey

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 to use an anonymous method for the OnTimer event instead of the old TNotifyEvent. The reason for this is that anonymous methods capture variables.
Since Delphi doesn’t offer this feature let’s implement it ourself.
Let’s start with a new unit and we will derive from the existing TTimer.

unit FMX.Types.AnonymousTimer;

interface

uses
  System.SysUtils, System.Classes, FMX.Types;

type
  TTimer = class(FMX.Types.TTimer)
  ...
  end;

I’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.
First, let’s add a property for the anonymous method.

...
  TTimer = class(FMX.Types.TTimer)
  strict private
    FOnTimerA: TProc;
    ...
  public
    property OnTimerA: TProc read FOnTimerA write FOnTimerA;
  end;

After we added the new property we have to call it. That’s why I will override the DoOnTimer method.

...
  TTimer = class(FMX.Types.TTimer)
  strict private
    FOnTimerA: TProc;
  strict protected
    procedure DoOnTimer; override;
  public
    property OnTimerA: TProc read FOnTimerA write FOnTimerA;
  end;

implementation

{ TTimer }

procedure TTimer.DoOnTimer;
begin
  if Assigned(FOnTimerA) then
    FOnTimerA
  else
    inherited DoOnTimer;
end;

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.

unit FMX.Types;
...
procedure TTimer.UpdateTimer;
begin
  KillTimer;
  if (FEnabled) and (FInterval > 0) and 
    (([csDesigning, csLoading, csDestroying] * ComponentState = [])) and
    Assigned(FOnTimer) then
  begin
    ...
  end;
  ...
end;

That’s why we need a dummy OnTimer event.

unit FMX.Types.AnonymousTimer;

interface

uses
  System.SysUtils, System.Classes, FMX.Types;

type
  TTimer = class(FMX.Types.TTimer)
  strict private
    FOnTimerA: TProc;
    procedure OnTimerDummy(Sender: TObject);
  strict protected
    procedure DoOnTimer; override;
  public
    constructor Create(AOwner: TComponent); override;
    property OnTimerA: TProc read FOnTimerA write FOnTimerA;
  end;

implementation

{ TTimer }

constructor TTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  OnTimer := OnTimerDummy;
end;

procedure TTimer.DoOnTimer;
begin
  if Assigned(FOnTimerA) then
    FOnTimerA
  else
    inherited DoOnTimer;
end;

procedure TTimer.OnTimerDummy(Sender: TObject);
begin
  //This is only a dummy event so that the OnTimer event is assigned.
end;

end.

Okay, that’s it. Now we have a TTimer with an anonymous method. I guess we should use it then. 🙂

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.

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.

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
  FMX.StdCtrls, FMX.Types.AnonymousTimer;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Timer1: TTimer;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  I := 0;
  Timer1.OnTimerA := procedure
  begin
    Inc(I);
    if I > 100 then
      I := 0;
    Label1.Text := I.ToString;
  end;
end;

end.

The result is a label which shows the expired seconds until 100.

Posted in FireMonkey, Tips and Tricks | Tagged , | Comments Off on Anonymous Timer and FireMonkey

SynEdit and Admin Rights

Today I’ve been able to get full admin rights to the SynEdit SourceForge project. This allows me to modify the download file which I updated immediately.

Posted in Third Party Components, Uncategorized | Comments Off on SynEdit and Admin Rights

VirtualTree and XE4

Today I also ported the VirtualTree component to XE4. The VirtualTree has been created by Mike Lischke. On his website he gives some information about this component:

“Virtual Treeview is a treeview control built from ground up. More than 13 years of development made it one of the most flexible and advanced Delphi tree controls available today. Virtual Treeview starts off with the claim to improve many aspects of existing solutions and introduces some new technologies and principles which were not available before.”

Posted in Third Party Components | Comments Off on VirtualTree and XE4

SynEdit and XE4

Today I added XE4 support to SynEdit. SynEdit is a nice syntax highlighting editor for Delphi which you can also find under SourceForge: “SynEdit is a syntax highlighting edit control, not based on the Windows common controls. SynEdit is compatible with both Delphi and Kylix (C++ Builder mostly works, but is unsupported).”

Since I’m not the admin of this SourceForge project I only added my changes to svn. I also uploaded the files in the EMBT discussion forum under attachments.

Posted in Third Party Components | Tagged , | Comments Off on SynEdit and XE4

Abbrevia and XE4

Abbrevia is also one of the good old TurboPower components like Orpheus. It is also hosted at SourceForge and it is maintained by Craig Peterson, one of the Beyond Compare developers. You can read at SourceForge the following:

“Abbrevia is a compression toolkit for Delphi, C++Builder, Kylix, and Free Pascal.

It supports compressing and decompressing PKZIP, Microsoft CAB, tar, gzip, and bzip2 archives, and can create self-extracting executables. On Windows it also provides Delphi wrappers for the LZMA, Bzip2, and WavPack SDKs, and PPMd decompression.

Abbrevia also has several visual controls that simplify displaying and manipulating archives, including treeview and listview components.”

Abbrevia now also supports XE4.

Posted in Third Party Components | Tagged , , | Comments Off on Abbrevia and XE4

Orpheus and XE4

Orpheus is a very old VCL component suite for Delphi. It started with Delphi 1 and supports all Delphi versions including XE4. It also supports the C++Builder.

Orpheus has originally been created by the great TurboPower company which closed their business on January 7, 2003. All their components including Orpheus can now be found at SourceForge.

Although Orpheus theoretically supports all Delphi versions I’m currently running XE2, XE3 and XE4 on my developing machine, and I will remove XE2 within the next weeks. This means that I can only give support for this versions, which is another reason to move to current Delphi versions.

Posted in Third Party Components | Tagged , | Comments Off on Orpheus and XE4

PowerPDF for XE4

Today I added support for XE4 to the PowerPDF component. As I already explained in an older post PowerPDF is a Delphi VCL component that allows to create pdf documents visually. PowerPDF supports the Delphi version 2007, 2010, XE, XE2, XE3 and since today XE4. You can download PowerPDF from Sourceforge or you can get it via svn. You will also find the link to svn at SourceForge.

Posted in Third Party Components | Tagged | Comments Off on PowerPDF for XE4

Indexing of Strings

As everyone knows Delphi strings are 1-based. This means that they are starting at the index 1 and ending at the index “Length()”. The reason is that Borland made the huge strings compatible to the old ShortStrings that had a length byte at the position 0.

I have to admit that I’m not happy about this fact since every TList and dynamic array are 0-based. All other important programming languages also have 0-based strings. I guess and also have the impression that EMBT will change this.

Certainly this will break all the old Delphi code. But for new code that you will write in the future you can do it in the way that it will work with 0- and 1-based strings.

Let’s look at an example:

...
var
  I: Integer;
  sBuffer: string;
begin
  sBuffer := 'Hallo World!';
  for I := 1 to Length(sBuffer) do
    Writeln(sBuffer[I]);
  Readln;
end.
...

As you can see there is the “1” and the “Length”. This code only works with 1-based strings. With the help of Low and High you can write it in a more flexible way:

...
var
  I: Integer;
  sBuffer: string;
begin
  sBuffer := 'Hallo World!';
  for I := Low(sBuffer) to High(sBuffer) do
    Writeln(sBuffer[I]);
  Readln;
end.
...

Please consider that Low works for strings in general. This means that you can also write the code in this way:

...
var
  I: Integer;
  sBuffer: string;
begin
  sBuffer := 'Hallo World!';
  for I := Low(string) to High(sBuffer) do
    Writeln(sBuffer[I]);
  Readln;
end.
...

With the help of the new record helpers you can also write it more object-oriented:

...
type
  TStringHelper = record helper for string
  public
    function High: Integer; inline;
    class function Low: Integer; static; inline;
  end;

{ TStringHelper }

function TStringHelper.High: Integer;
begin
  Result := System.High(Self);
end;

class function TStringHelper.Low: Integer;
begin
  Result := System.Low(string);
end;

var
  I: Integer;
  sBuffer: string;
begin
  sBuffer := 'Hallo World!';
  for I := sBuffer.Low to sBuffer.High do
    Writeln(sBuffer[I]);
  Readln;
end.
...

Let’s see which features EMBT will bring to XE4 in the future, please stay tuned…

Posted in Tips and Tricks | Tagged | Comments Off on Indexing of Strings

Record Helpers for Intrinsic Types, Part 3 – Update

As I already told you, I’m using the great record helpers for intrinsic types. XE3 already ships with the TStringHelper which is defined in System.SysUtils. I looked at the implementation and there a some parts that make me really disappointed.

...
function TStringHelper.IsEmpty: Boolean;
begin
  if Self = Empty then
    Result := True
  else
    Result := False;
end;
...

Come on guys, this is a bad joke! Everyone who works at least one day with Delphi knows that he can write this code in one simple line.

...
function TStringHelper.IsEmpty: Boolean;
begin
  Result := Self = Empty;
end;
...

I really hope that his issue will be fixed in XE4…

I just installed XE4 and it has been fixed! Another reason to move to XE4…

Posted in Tips and Tricks | Tagged | Comments Off on Record Helpers for Intrinsic Types, Part 3 – Update

Record Helpers for Intrinsic Types, Part 2 – Update

This week I used some record helpers for intrinsic types and I think that they are a wonderful feature. This means that you should update at least to XE3 to use this great feature.

But as always there are some issues: I had an resourcestring and wanted to access to the length.

program TestHelper;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

resourcestring
  SAnswer = '42';

begin
  Writeln('The length of ' + SAnswer + ' is:');
  Writeln(SAnswer.Length);
  Readln;
end.

I tried to compile this code and it doesn’t! The compiler doesn’t know the method length although in System.SysUtils there is the TStringHelper with this method! I had been very surprised but then I thought that a resourcestring is not a string but only assignable to a string, something like a type string.

With XE4 this code does compile which is the expected behavior! Many thanks for this fix.

I talked about this issue to a friend (Many thanks to him!) and he told me that I should try a record helper for a WideString.

program TestHelper;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

resourcestring
  SAnswer = '42';

type
  TWideStringHelper = record helper for WideString
  public
    function Length: Integer; inline;
  end;

{ TWideStringHelper }

function TWideStringHelper.Length: Integer;
begin
  Result := System.Length(Self);
end;

begin
  Writeln('The length of ' + SAnswer + ' is:');
  Writeln(SAnswer.Length);
  Readln;
end.

And this code does compile! This means that a resourcestring is a WideString. Again, I’m surprised. But run this small project. It shows that the length of ’42’ is 1. This is a bug!!! My friend told me that a there is already the Quality Central item 112844 for this bug. This means that you shouldn’t use a record helper for resourcestrings in XE3. I hope that this bug will be fixed in XE4, so stay tuned….

Again, under XE4 the resourcestring works like a string. This means that a TWideStringHelper doesn’t work, instead the TStringHelper does. And the length is the correct value. So many thanks for this fix. This is a very good reason to move to XE4.

Posted in Tips and Tricks | Tagged | Comments Off on Record Helpers for Intrinsic Types, Part 2 – Update