Delphi – indexed properties
Posted by jpluimers on 2009/07/23
Sometimes, indexed properties can make your life much easier: they allow you to redirect single properties to central Get/Set methods.
You don’t see it used very often, but when you need it, it is very handy.
There is even some online help on it (look for “Index Specifiers”) it gives you the basics, but no compiling example.
For me it works best when I have a complete, but concise example.
So here is one: TMyIndexedPropertyComponent that has property Range1Value through Range4Value of type TRange, all centralized to one pair of read/write methods: GetRangeValue and SetRangeValue.
First the type of the property itself: TRange (and the array: TRanges).
unit RangesUnit;
interface
const
MinRangeIndex = 0;
MaxRangeIndex = 3;
type
TRange = record
Value: Integer;
function Equals(const Range: TRange): Boolean;
end;
TRanges = array[MinRangeIndex..MaxRangeIndex] of TRange;
implementation
{ TRange }
function TRange.Equals(const Range: TRange): Boolean;
begin
Result := Self.Value = Range.Value;
end;
end.
Then the TMyIndexedPropertyComponent:
unit MyIndexedPropertyComponentUnit;
interface
uses
SysUtils, Classes, ExtCtrls,
RangesUnit;
type
TMyIndexedPropertyComponent = class(TPaintBox)
strict private
FRanges: TRanges;
strict protected
function GetRangeValue(Index: Integer): Integer; virtual;
procedure SetRangeValue(Index: Integer; const Value: Integer); virtual;
procedure SetRangeAndRepaint(Index: Integer; Range: TRange); virtual;
procedure SetRanges(const Value: TRanges); virtual;
public
constructor Create(aOwner: TComponent); override;
property Range1Value: Integer index 0 read GetRangeValue write SetRangeValue;
property Range2Value: Integer index 1 read GetRangeValue write SetRangeValue;
property Range3Value: Integer index 2 read GetRangeValue write SetRangeValue;
property Range4Value: Integer index 3 read GetRangeValue write SetRangeValue;
property Ranges: TRanges read FRanges write SetRanges;
end;
implementation
{ TMyIndexedPropertyComponent }
constructor TMyIndexedPropertyComponent.Create(aOwner: TComponent);
var
Range1: TRange;
Range2: TRange;
Range3: TRange;
Range4: TRange;
begin
inherited;
Width := 260;
Height := 160;
Range1.Value := 5;
Range1.Value := 15;
Range2.Value := 85;
Range3.Value := 110;
Range4.Value := 175;
FRanges[0] := Range1;
FRanges[1] := Range2;
FRanges[2] := Range3;
FRanges[3] := Range4;
end;
function TMyIndexedPropertyComponent.GetRangeValue(Index: Integer): Integer;
var
Range: TRange;
begin
Range := Self.Ranges[Index];
Result := Range.Value;
end;
procedure TMyIndexedPropertyComponent.SetRangeValue(Index: Integer; const Value: Integer);
var
Range: TRange;
begin
Range := Self.Ranges[Index];
if Range.Value <> Value then
begin
Range.Value := Value;
SetRangeAndRepaint(Index, Range);
end;
end;
procedure TMyIndexedPropertyComponent.SetRangeAndRepaint(Index: Integer; Range: TRange);
begin
Self.FRanges[Index] := Range; //jpl: not: Ranges[Index]!! (you will assign a copy if you do)
Repaint();
end;
procedure TMyIndexedPropertyComponent.SetRanges(const Value: TRanges);
var
Equals: Boolean;
Index: Integer;
begin
Equals := True;
for Index := MinRangeIndex to MaxRangeIndex do
Equals := Equals and FRanges[Index].Equals(Value[Index]);
if not Equals then
begin
FRanges := Value;
Repaint;
end;
end;
end.
And finally an example on how to use both the Ranges property and the individual Range1Value through Range4Value properties:
program IndexedPropertyDemoProject;
{$APPTYPE CONSOLE}
uses
SysUtils,
RangesUnit in 'RangesUnit.pas',
MyIndexedPropertyComponentUnit in 'MyIndexedPropertyComponentUnit.pas';
var
MyIndexedPropertyComponent: TMyIndexedPropertyComponent;
Ranges: TRanges;
begin
try
MyIndexedPropertyComponent := TMyIndexedPropertyComponent.Create(nil);
try
Ranges := MyIndexedPropertyComponent.Ranges;
MyIndexedPropertyComponent.Ranges := Ranges;
MyIndexedPropertyComponent.Range1Value := 1;
MyIndexedPropertyComponent.Range1Value := 2;
MyIndexedPropertyComponent.Range1Value := 3;
MyIndexedPropertyComponent.Range1Value := 4;
finally
MyIndexedPropertyComponent.Free;
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.






uligerhardt said
“There is _even_ some online help” for a language feature – that’s funny.
jpluimers said
(: