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 Eigene VCL-Komponenten, die ein Interface implementieren (https://www.delphipraxis.net/143518-eigene-vcl-komponenten-die-ein-interface-implementieren.html)

MatthiasR 17. Nov 2009 15:32


Eigene VCL-Komponenten, die ein Interface implementieren
 
Folgende Situation: ich möchte mir eine Sammlung einiger Standard-WinControls (Edits, Checkbox, Listbox...) erstellen, die allesamt folgendes von mir definiertes Interface implementieren sollen:
Delphi-Quellcode:
ILoadAndSaveToXml = interface(IInterface)
  ['{C565EF46-47C1-482D-9C71-4570B555BBA4}']            
  function GetAutoLoadAndSaveToXml: Boolean;
  procedure SetAutoLoadAndSaveToXml(const Value: Boolean);
  property AutoLoadAndSaveToXml: Boolean read GetAutoLoadAndSaveToXml write SetAutoLoadAndSaveToXml;
                                                         
  procedure LoadFromXml(const XmlElement: IXMLDOMElement);
  procedure SaveToXml(const XmlElement: IXMLDOMElement);
end;
Es sollen also alle Controls über die Methoden LoadFromXml, SaveToXml und die property AutoLoadAndSaveToXml verfügen.

Anschließend möchte ich in einer Anwendung mittels ComponentCount alle vorhandenen Controls durchlaufen, schauen ob sie das besagte Interface ILoadAndSaveToXml unterstützen und falls ja, die besagten Methoden aufrufen.

Frage: wie mache ich das?

Das habe ich bisher versucht:

Ich habe mir z.B. ein eigenes Edit wie folgt deklariert:
Delphi-Quellcode:
TMyEdit = class(TEdit, ILoadAndSaveToXml)
private
  FAutoLoadAndSaveToXml: Boolean;
  function GetAutoLoadAndSaveToXml: Boolean;
  procedure SetAutoLoadAndSaveToXml(const Value: Boolean);
published
  property AutoLoadAndSaveToXml: Boolean read GetAutoLoadAndSaveToXml write SetAutoLoadAndSaveToXml;

  procedure LoadFromXml(const XmlElement: IXMLDOMElement);
  procedure SaveToXml(const XmlElement: IXMLDOMElement);
end;
Die Methoden habe ich mit entsprechendem Leben gefüllt. Theoretisch müsste ich auch noch QueryInterface und _AddRef und _Release selbst implementieren, da meine ganzen Controls ja nicht von TInterfacedObject abgeleitet sind, aber das hab ich erstmal weg gelassen.

Alles schön und gut, nur wie finde ich nun zur Laufzeit heraus, ob eine Komponente auf dem Formular das Interface ILoadAndSaveToXml unterstützt, damit ich die Methoden aufrufen kann? Theoretisch ginge das ja über QueryInterface, aber das steht mir nur bei meinen eigenen Controls zu Verfügung, nicht bei allen anderen, die keine von IInterface abgeleitete Schnittstelle implementieren, oder? Oder ist das, was ich hier gerade versuche, ohnehin völliger Blödsinn :shock: ? Also Controls, die zusätzlich Interfaces implementieren?

Danke für eure Hilfe!

GPRSNerd 17. Nov 2009 15:47

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Zwei mögliche Ansätze, mit denen ich in einer eigenen Komponente arbeite, hätte ich hier:

1)
Delphi-Quellcode:
if IsPublishedProp(Control, 'AutoLoadAndSaveToXml') then ...
2)
Delphi-Quellcode:
if (Control is TMyEdit) then ...
Vielleicht gibts zu IsPublishedProp ein Äquivalent für Methoden...

Bernhard Geyer 17. Nov 2009 15:51

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Zitat:

Zitat von MatthiasR
... ohnehin völliger Blödsinn :shock: ?

Wäre ein schöner Ansatz wenn du nicht gefahr läufst das du dir permanent ins Knie schießt (Automatische Freigabe von Interfaces obwohl noch objektzeiger vorhanden sind)...

Bei Delphi sollte man entweder über Interfaces Arbeiten oder Interfaces komplett links liegen lassen. Gemischter Betrieb klappt fast nie. Mussten schon Tage an Fehlersuche investieren bis wir herausgefunden hatten wiesoe unsere App hin und wieder krachte. Und da VCL-Komponenten beim erzeugen einen Owner verwenden hättest du fast immer den gefährlichen gemischten Betrieb.

MatthiasR 17. Nov 2009 15:53

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Zitat:

Zitat von GPRSNerd
1)
Delphi-Quellcode:
if IsPublishedProp(Control, 'ReadOnly') then ...
2)
Delphi-Quellcode:
if (Control is TMyEdit) then ...

Letzteres wäre auch mein nächster Ansatz gewesen, wobei ich dann alle potentiell möglichen Klassen berücksichtigen müsste. Also:
Delphi-Quellcode:
if (Control is TMyEdit) or (Control is TMyListBox) or (Control is TMyComboBox) or ...
Ein simples
Delphi-Quellcode:
if Control.Supports(ILoadAndSavetoXml) then ...
wäre mir lieber, wenn es das denn gäbe. So könnte ich nach und nach immer mehr Controls in meine Bibliothek mit aufnehmen, die das Interface implementieren, ohne an dem Formular irgendwelche Änderungen vornehmen zu müssen.

GPRSNerd 17. Nov 2009 15:56

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Geht doch mit dem ersten Ansatz, insofern alle deine Kompos z.B. die Property "AutoLoadAndSaveToXml" unterstützen:

Delphi-Quellcode:
if IsPublishedProp(Control, 'AutoLoadAndSaveToXml') then ...

Namenloser 17. Nov 2009 16:45

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Funktioniert der Operator "is" nicht bei Interfaces?

Bernhard Geyer 17. Nov 2009 16:46

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Zitat:

Zitat von NamenLozer
Funktioniert der Operator "is" nicht bei Interfaces?

AFAIK nur wenn du für das Interface eine GUID vergibst.

Hawkeye219 17. Nov 2009 17:00

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Hallo Matthias,

alle von TComponent abgeleiteten Komponenten implementieren (in TComponent) das Interface IInterface - also auch deine speziellen Controls, ohne dass du die entsprechenden Funktionen selbst programmieren musst. Zusätzlich ist in TComponent die Referenzzählung ausgeschaltet, falls du nicht gerade mit COM hantierst und Controls ableitest, die das Interface IVCLComObject implementieren.

Die einfache Abfrage lautet daher

Delphi-Quellcode:
var
  intf: ILoadAndSaveToXml;
begin
  if Supports(Component, ILoadAndSaveToXml, intf) then
    intf.SaveToXML (...);
end;
Für alle nicht von TComponent abgeleiteten Klassen gelten natürlich die von Bernhard gemachten Aussagen bezüglich der gemischten Verwendung von Interface- und Objektreferenzen.

Gruß Hawkeye

MatthiasR 18. Nov 2009 08:02

Re: Eigene VCL-Komponenten, die ein Interface implementieren
 
Zitat:

Zitat von Bernhard Geyer
Zitat:

Zitat von NamenLozer
Funktioniert der Operator "is" nicht bei Interfaces?

AFAIK nur wenn du für das Interface eine GUID vergibst.

Das hatte ich zu aller erst ausprobiert. Zumindest bei mir beschwert sich der Compiler, wenn ich
Delphi-Quellcode:
if (Components[i] is ILoadAndSaveToXml) then
mit folgender Fehlermeldung:
Zitat:

[Fehler] Unit1.pas(39): Operator ist auf diesen Operandentyp nicht anwendbar
Obwohl ich dem Interface eine GUID verpasst habe. Wenn es direkt mit "is" geklappt hätte, hätte ich die Frage hier nicht gestellt :-D
Zitat:

Zitat von Hawkeye219
Hallo Matthias,

alle von TComponent abgeleiteten Komponenten implementieren (in TComponent) das Interface IInterface - also auch deine speziellen Controls, ohne dass du die entsprechenden Funktionen selbst programmieren musst. Zusätzlich ist in TComponent die Referenzzählung ausgeschaltet, falls du nicht gerade mit COM hantierst und Controls ableitest, die das Interface IVCLComObject implementieren.

Die einfache Abfrage lautet daher

Delphi-Quellcode:
var
  intf: ILoadAndSaveToXml;
begin
  if Supports(Component, ILoadAndSaveToXml, intf) then
    intf.SaveToXML (...);
end;
Für alle nicht von TComponent abgeleiteten Klassen gelten natürlich die von Bernhard gemachten Aussagen bezüglich der gemischten Verwendung von Interface- und Objektreferenzen.

Gruß Hawkeye

Hallo Hawkeye,

danke für die Hintergrundinfos bezüglich TComponent und der "Supports"-Funktion. Genau die haben mir gefehlt. Klar, wenn TComponent bereits IInterface implementiert, dann tun das auch alle WinControls. So muss ich mich dann doch nicht selbst drum kümmern. Außerdem bin ich dann beim Implementieren zusätzlicher Interfaces in meinen eigenen Controls immer auf der sicheren Seite, ohne dass mir die Referenzzählung dabei in die Quere kommt (solange ich die IInterface-Methoden nicht überschreibe). Habs auch schon ausgetestet, funktioniert astrein =) . Womit ich soeben mein erstes eigenes Interface definiert hätte, das noch dazu nen richtig sinnvollen Zweck erfüllt :lol:
:dp:


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:11 Uhr.

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