How to use interfaces?

Hi, all
I would like to create some components that all implement an interface, say IMyInterface, and then in a form check for the components that implement the interface. In other words, if:

TClass1 = class(TGraphicControl,IMyInterface)
  ...
end;

TClass1 = class(TGraphicControl,IMyInterface)
  ...
end;

then in my form I would like to do

for i:=0 to ComponentCount-1 do
begin
  if Components[i] is IMyInterface then
  begin
    //....
  end;
end;

Is that possible, or is there any other way to check if a component implements an interface and to typecast it?
LVL 3
karouriAsked:
Who is Participating?
 
TOndrejCommented:
Hi karouri, here is a very basic/simple example of implementing interfaces by delegation:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  ISomething = interface
    ['{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}'] // generate your own GUID (Ctrl+Shift+G)
    procedure DoSomething;
  end;
  TSomething = class(TComponent, ISomething)
  protected
    procedure DoSomething;
  end;
  TMyControl1 = class(TGraphicControl, IUnknown, ISomething)
  private
    FSomething: TSomething;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Something: TSomething read FSomething write FSomething implements ISomething;
  end;
  TMyControl2 = class(TMyControl1)
  protected
    procedure Paint; override;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{ TSomething protected }

procedure TSomething.DoSomething;
begin
  ShowMessage('Huh?');
end;

{ TMyControl1 protected }

procedure TMyControl1.Paint;
begin
  with Canvas do
  begin
    Brush.Color := clRed;
    FillRect(ClientRect);
    TextOut(8, 8, Format('This is %s [%s]', [Self.Name, Self.ClassName]));
  end;
end;

{ TMyControl1 public }

constructor TMyControl1.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSomething := TSomething.Create(nil);
end;

destructor TMyControl1.Destroy;
begin
  FSomething.Free;
  inherited Destroy;
end;

{ TMyControl2 protected }

procedure TMyControl2.Paint;
begin
  with Canvas do
  begin
    Brush.Color := clGreen;
    FillRect(ClientRect);
    TextOut(8, 8, Format('This is %s [%s]', [Self.Name, Self.ClassName]));
  end;
end;

{ TForm1 event handlers }

procedure TForm1.FormCreate(Sender: TObject);
begin
  with TMyControl1.Create(Self) do
  begin
    Parent := Self;
    Name := 'MyControl1';
    SetBounds(0, 0, 200, 100);
  end;
  with TMyControl2.Create(Self) do
  begin
    Parent := Self;
    Name := 'MyControl2';
    SetBounds(0, 200, 200, 100);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  Something: ISomething;
begin
  for I := 0 to ComponentCount - 1 do
    if Supports(Components[I], ISomething, Something) then
      Something.DoSomething;
end;

end.

HTH
TOndrej
0
 
JaccoCommented:
Something like this should work:

var
  lMyIntf: IMyInterface;
begin
  for i:=0 to ComponentCount-1 do
  begin
    if Supports(Components[i], IMyInterface, lMyIntf) then
    begin
      lMyIntf.DoInterfaceThing(...);
    end;
  end;
end;

Regards Jacco
0
 
ginsonicCommented:
listening
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
TOndrejCommented:
Jacco: I believe you need to set IMyIntf := nil; in each iteration of the loop, to decrease reference count
0
 
karouriAuthor Commented:
I thinl you are right, Jacco. But I think that this needs a QueryInterface definition on TClass1 and TClass2, and I wasn't able to do it.
As for the reference count, it happens that TClass1 & TClass2 are components, so I will define _AddRef and _Release to skip memory management..
k
0
 
karouriAuthor Commented:
Excellent, TOndrej. That does exactly what I want. And thanks everyone.
btw, is it as simple to do it without delegation?
0
 
TOndrejCommented:
Hi karouri,

Thanks for the points.

TGraphicControl inherits IUnknown support from TComponent which bypasses reference counting (except for ActiveX-ed controls), so you could simply (re)implement the interface in every control, e.g.

class
  TMyControl1 = class(TGraphicControl, ISomething)
  protected
    procedure DoSomething; virtual; // make it virtual if you want to give descendants a possibility to override
  end;

In fact, that's possibly a better option for you, depending on what you want to do...

If the interface implementation is going to be very similar for each control (and there will be many controls) then it might be better to have a separate base implementor class and use delegation (each control could delegate to a descendant but most funcionality would already be implemented in the base class)

If it doesn't sound like worth all the work or every control will implement the interface differently (so having a base implementor class doesn't make sense), then simply implement your interface in every control, as shown above.

HTH
0
 
karouriAuthor Commented:
Thanks TOndrej, I have done it without delegation. But as I tested it here, mentioning IUnknown in the interface is a must, like:
  TMyControl2 = class(TGraphicControl, IUnknown, ISomething)
  private
    FSomething: TSomething;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DoSomeThing;
  end;
If you omit IUnknown then the Supports function will work but will not find TMyControl2. That was one of my errors in the first place.
Thanks again
k
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.