December 30, 2012
Writing an iterator for a container
In my last article I explained how to write a class property being a list of integers and how to write the corresponding property editor. We wrote TIntegerList class which merely looks like the well known TStringList class except it contains integers instead of strings.
Today, we will add some code to TIntegerList class so that we can use the for..in Delphi construct. Without this construct, the code to iterate thru the list of integers and display those in a TMemo looks like this:
procedure TForm1.EnumeratorButtonClick(Sender: TObject);
var
I, N : Integer;
begin
for N := 0 to TickLine1.TickPos.Count - 1 do begin
I := TickLine1.TickPos[N];
Memo1.Lines.Add(IntToStr(I));
end;
end;
Using this for..in construct greatly simplifies the code:
procedure TForm1.EnumeratorButtonClick(Sender: TObject);
var
I : Integer;
begin
for I in TickLine1.TickPos do
Memo1.Lines.Add(IntToStr(I));
end;
For the compiler to be able to iterate thru our TIntegerList class (A "container" in Delphi terminology), we must implement a new public method GetEnumerator() function which has to return a class, a record or an interface. In my example, I will use a class.
The class must contain a function MoveNext() returning a boolean and a property Current returning the current element of the container.
We will name the enumerator class TIntegerListEnumerator. To help you better understand here is the code the compiler actually generates when you write the code above:
procedure TForm1.EnumeratorButtonClick(Sender: TObject);
var
I : Integer;
Enum : TIntegerListEnumerator;
begin
Enum := TickLine1.GetEnumerator();
try
while Enum.MoveNext do begin
I := Enum.Current;
Memo1.Lines.Add(IntToStr(I));
end;
finally
Enum.Free;
end;
end;
Remember, you don't write this code, it is generated by the compiler when you write the "for I in".
The code is quite easy to understand. The actual enumeration is done by the class TIntegerListEnumerator we have to write once. And it is trivial to write it. Here is the source code:
TIntegerListEnumerator = class
private
FIndex : Integer;
FIntegers : TIntegerList;
public
constructor Create(const AIntegers: TIntegerList);
function GetCurrent: Integer; inline;
function MoveNext: Boolean;
property Current: Integer read GetCurrent;
end;
constructor TIntegerListEnumerator.Create(const AIntegers: TIntegerList);
begin
inherited Create;
FIndex := -1;
FIntegers := AIntegers;
end;
function TIntegerListEnumerator.GetCurrent: Integer;
begin
Result := FIntegers[FIndex];
end;
function TIntegerListEnumerator.MoveNext: Boolean;
begin
Result := FIndex < (FIntegers.Count - 1);
if Result then
Inc(FIndex);
end;
The class has two variables: FIndex and FIntegers. FIndex will be used to iterate thru all values and FIntegers will reference the values to be iterated.
The construction takes one argument which is the integer list to iterate. It initializes the FIndex variable to -1 which is the starting value since it gets incremented before each iteration by MoveNext.
The procedure MoveNext has two responsibilities: increment the iteration variable and return the status of the iteration. If MoveNext returns TRUE, then it means there are more items in the list.
The property Current, implemented using the setter GetCurrent simply returns the integer whose index is given by the iteration variable FIndex.
That all we need for the iteration class!
The actual container class, TIntegerList need only one public method: GetEnumerator. The code is really simple:
function TIntegerList.GetEnumerator: TIntegerListEnumerator;
begin
Result := TIntegerListEnumerator.Create(Self);
end;
That's it !
Note: Have a look at Internet Component Suite (ICS)
December 24, 2012
TIntegerList property and property editor
A few weeks
ago, I was faced with the problem of designing a component having a list of
integer as a property. This is quite easy to write, but once installed in the
IDE, this property cannot be edited using the object inspector! Actually, the property
is not even serialized in the DFM.
After a few
Google searches, I came to the conclusion that no code was readily available
for the purpose. So I wrote it and now I'm making it available thru this blog
article.
This
article is made of:
1 A simple custom visual component
using a list of integers as property. This component has been made very simple
(and mostly useless) so that you can concentrate of our today's subject: the
property made of a list of integers.
2 A simple demo application showing
the component in action at runtime and reusing the property editor in the
application (normally a property editor is only used by the IDE).
3 A class to implement the list of
integers. It looks much like TStringList class. Instead of a list of strings,
we get a list of integers.
4 A property editor so that the list
of integer could be edited from the object inspector at design time.
Read more: TIntegerList property and property editor
Have a look at Internet Component Suite (ICS)
December 11, 2012
Delphi XE3 and C++Builder XE3 Update 1 ISO available
The ISO track for Delphi XE3 and C++Builder XE3 is available now for registered users of the product. It include update 1 built-in. Download form here
This ISO can be used to burn a DVD or can be directly mounted with such tool as Daemon Tools Lite.
This ISO can be used to burn a DVD or can be directly mounted with such tool as Daemon Tools Lite.
Subscribe to:
Posts (Atom)