Solved

How to use interfaces?

Posted on 2001-09-05
8
149 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
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
 
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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

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…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

743 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now