Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TObjectList als Komponente (https://www.delphipraxis.net/104433-tobjectlist-als-komponente.html)

oki 4. Dez 2007 07:00


TObjectList als Komponente
 
Hi Leute,

ich habe eine spezialisierte Klasse von TObjectList erstellt. Jetzt möchte ich diese als Komponente haben. Bis dato war meine Vorgehensweise immer diese:
Delphi-Quellcode:
type
  TBaseTransactionList = class(TObjectList)
  private
  protected
    function GetItem(Index: Integer): TTransactionObj;
    procedure SetItem(Index: Integer; AObject: TTransactionObj);
  public
    function Add(AObject: TTransactionObj): Integer; virtual;
    function Extract(Item: TTransactionObj): TTransactionObj;
    function Remove(AObject: TTransactionObj): Integer;
    function IndexOf(AObject: TTransactionObj): Integer;
    procedure Insert(Index: Integer; AObject: TTransactionObj);
    function First: TTransactionObj;
    function Last: TTransactionObj;
    property Items[Index: Integer]: TTransactionObj read GetItem write SetItem; default;
  end;

  TTransactionList = class(TBaseTransactionList)
  private
    FBreakTransaction : Boolean;       // Flag für Abbruch der Abarbeitung
    FExecuteTransIndex : Integer;      // Index der aktuell in der Abarbeitung befindlichen Transaktion
    FExecuteTransObj: TTransactionObj; // Transaction-Object, dass gerade abgearbeitet wird (Execute läuft)
  protected
    function AddNewTransaction(ADevice : TRemoteDevice; APhone : TBasePhoneObj; Action : TActionObj) : Integer;
    procedure TransmitNextTransaction; virtual;
  public
    Constructor Create; reintroduce; virtual;

    function GetTransactionObj(ADevice : TRemoteDevice; APhone : TBasePhoneObj) : TTransactionObj; overload;
    function GetTransactionObj(ADevice : TRemoteDevice; APhoneNumber : String) : TTransactionObj; overload;
    procedure AddAction(ADevice : TRemoteDevice; APhone : TBasePhoneObj; Action : TActionObj);

    procedure BreakTransaction; virtual;
    procedure ExecuteTransaction(APhoneNumber : string); overload; virtual;
    procedure ExecuteTransaction(ATransaction : TTransactionObj); overload; virtual;
    procedure ExecuteTransactions; virtual;
  end;

  TCompTransactionList = class(TComponent)
  private
    FTransactionList : TTransactionList;         // Transaktionsliste
  protected
  public
    Constructor Create(AOwner : TComponent); override;
    Destructor Destroy; override;
  published
  end;
Im Constructor der Komponente wird nun meine TransactionList kreiert und im destruktor wieder zerstört. Alle Zugriffe laufen dann über die Componente. Entweder ich mache FTransactionList öffentlich, oder implementiere Alle Methoden von FTransactionList noch einmal in der Componente im Public Teil.
Nun, ich dächte, das könnte man dann aber auch mit Interfaces haben.

Etwa so:
Delphi-Quellcode:
  TCompTransactionList = class(TComponent, ITransactionList)
  private
  protected
  public
    ...........
Nun hab ich mir einiges zu Interfaces durchgelesen. Das war soweit auch verständlich. Leider mach ich mir hier ein paar Sorgen das für meinen konkreten Fall korrekt hinzubekommen. Folgende Probleme und Fragen stellen sich mir:

1. Kann man so einfach eine abgeleitete ObjectList zum Interface machen?
Mein Bsp.:
Delphi-Quellcode:
type
  ITransactionList = interface(IInterface)          // abgeleitet von IInterface
  ['{677854F0-525B-4372-9C7A-F87A00A8A117}'] // der GUID des Interface
    function GetTransactionObj(ADevice : TRemoteDevice; APhone : TBasePhoneObj) : TTransactionObj; overload;
    function GetTransactionObj(ADevice : TRemoteDevice; APhoneNumber : String) : TTransactionObj; overload;
    procedure AddAction(ADevice : TRemoteDevice; APhone : TBasePhoneObj; Action : TActionObj);

    procedure BreakTransaction; virtual;
    procedure ExecuteTransaction(APhoneNumber : string); overload; virtual;
    procedure ExecuteTransaction(ATransaction : TTransactionObj); overload; virtual;
    procedure ExecuteTransactions; virtual;
end;
Ich kann mir nicht so richtig vorstellen, dass das reichen soll. Die Basisklasse TObjectList hat da ja noch ne Menge mehr an Methoden und Eigenschaften.

Dann die nächste Frage:

TComponent ist wohl nicht von IInterfacedObject abgeleitet (glaub ich). Damit müßte das nicht so ohne weiteres klappen:
Delphi-Quellcode:
  TCompTransactionList = class(TComponent, ITransactionList)
  private
  protected
  public
    function GetTransactionObj(ADevice : TRemoteDevice; APhone : TBasePhoneObj) : TTransactionObj; overload;
    function GetTransactionObj(ADevice : TRemoteDevice; APhoneNumber : String) : TTransactionObj; overload;
    procedure AddAction(ADevice : TRemoteDevice; APhone : TBasePhoneObj; Action : TActionObj);

    procedure BreakTransaction; virtual;
    procedure ExecuteTransaction(APhoneNumber : string); overload; virtual;
    procedure ExecuteTransaction(ATransaction : TTransactionObj); overload; virtual;
    procedure ExecuteTransactions; virtual;
Tja, wenn mir da einer helfen kann????????


Gruß oki

Bernhard Geyer 4. Dez 2007 08:05

Re: TObjectList als Komponente
 
Bei Controls die von TComponent abgeleitet sind und damit aufs Formular gelegt werden können und damit einen Parent hat welcher automatisch die Freigabe beim eigenen Zerstören erledigt sollte man mit Interfaces aufpassen, da du hiermit deinem Interface-Zeiger "hinterrücks" das lebende Objekt zerstörst. Hat mir (und Kollegen) schon ein paar Tage Fehlersuche gekostet.
Am besten der Komponenten kein Interface verpassen und erst in internen Objekten mit Interfaces arbeiten.

oki 4. Dez 2007 08:14

Re: TObjectList als Komponente
 
Hallo Bernhardt,
so dachte ich auch. Deshalb mein bisheriger Ansatz mit der "eingebetteten" Liste.
Als ich aber mal bei den Jedis in den Source geschaut habe ist mir aufgefallen, dass dort Componenten teilweise auch Interfaces in der Klassenableitung haben. Richtig hinter gestiegen bin ich da zwar nicht, aber auch daher kommt meine Vermutung, dass man das machen kann.
Nun will ich's mir aber auch nicht unnötig kompliziert machen. Ich bin im aktuellen Projekt auch mächtig unter Zeitdruck. Hatte halt die Hoffnung, dass es mit einem Inteface eleganter gelöst werden könnte.
Ich lass die Frage noch mal offen, wenn sich nicht interessantes mehr ergibt, erledige ich es auf meine Alt-Hergebrachte-Art.

Dank und Gruß
oki

shmia 4. Dez 2007 09:59

Re: TObjectList als Komponente
 
Zitat:

Zitat von oki
Als ich aber mal bei den Jedis in den Source geschaut habe ist mir aufgefallen, dass dort Componenten teilweise auch Interfaces in der Klassenableitung haben. Richtig hinter gestiegen bin ich da zwar nicht, aber auch daher kommt meine Vermutung, dass man das machen kann.

Ja, TComponent implementiert das Interface IUnknown auf spezielle Weise.
Wenn das Property VCLComObject = nil ist, dann wird die Referenzzählung ausser Kraft gesetzt und man kann
Objekt- und Interfacereferenzen mischen.
Also man kann folgendes schreiben:
Delphi-Quellcode:
TCompTransactionList = class(TComponent, ITransactionList)
...
var
   tl : TComponent;
   intf : ITransactionList
begin
   tl := TCompTransactionList.Create(nil);
   ...
   intf := tl as ITransactionList;
   intf.ExecuteTransactions;
   intf := nil; // wir haben Glück, das Objekt tl wird nicht zerstört
   ...
   tl.Free;

oki 4. Dez 2007 10:06

Re: TObjectList als Komponente
 
Hi shmia,

Licht und Schatten liegen so dicht beieinander.
Zitat:

a, TComponent implementiert das Interface IUnknown auf spezielle Weise.
Wenn das Property VCLComObject = nil ist, dann wird die Referenzzählung ausser Kraft gesetzt und man kann
Objekt- und Interfacereferenzen mischen.
soweit das, worauf ich gehofft habe.

Nun wollte ich im Code jedoch nicht meine Zugriffe trennen. Was ich erreichen will ist eigentlich das:
Delphi-Quellcode:
TCompTransactionList = class(TComponent, ITransactionList)
...
var
   tl : TCompTransactionList;
begin
   tl := TCompTransactionList.Create(nil);
   ...
   tl.ExecuteTransactions;
   ...
   tl.Free;
end;
Jo, so dachte ich.

Gruß oki


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:50 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz