Solved

How to use interfaces?

Posted on 2001-09-05
8
151 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
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
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

Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

Question has a verified solution.

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

Suggested Solutions

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 The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
This is used to tweak the memory usage for your computer, it is used for servers more so than workstations but just be careful editing registry settings as it may cause irreversible results. I hold no responsibility for anything you do to the regist…

816 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

13 Experts available now in Live!

Get 1:1 Help Now