The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,702 other followers

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.

2 Responses to “Delphi – indexed properties”

  1. uligerhardt said

    “There is _even_ some online help” for a language feature – that’s funny.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

 
%d bloggers like this: