Solved

How to use interfaces?

Posted on 2001-09-05
8
154 Views
Last Modified: 2010-04-06
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?
0
Comment
Question by:karouri
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
8 Comments
 
LVL 10

Expert Comment

by:Jacco
ID: 6458367
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
 
LVL 9

Expert Comment

by:ginsonic
ID: 6459488
listening
0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6460684
Jacco: I believe you need to set IMyIntf := nil; in each iteration of the loop, to decrease reference count
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 3

Author Comment

by:karouri
ID: 6460768
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
 
LVL 8

Accepted Solution

by:
TOndrej earned 200 total points
ID: 6460907
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
 
LVL 3

Author Comment

by:karouri
ID: 6461214
Excellent, TOndrej. That does exactly what I want. And thanks everyone.
btw, is it as simple to do it without delegation?
0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6461290
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
 
LVL 3

Author Comment

by:karouri
ID: 6461405
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

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi TcxGrid group footer summary 3 358
Intraweb download file link ? 1 167
find a node in VST 2 78
Twebbrowser add css to the header 3 39
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question