![]() |
TObject As Interface
Hi zusammen,
ich muss zugeben, ich weiß gerade nicht so recht, wie ich nach meinem Problem suchen kann, daher poste ich hier, auch wenn es möglicherweise schon eine Antowrt dazu irgendwo gibt. Es handelt sich hierbei um eine theoretische Frage, da ich das ganze im Projekt nun anders gelöst habe. Trotzdem würde ich gerne wissen, was ich falsch mache oder wie man das Problem reell lösen könnte. Ich habe eine vordefinierte Quelle in welchem ich Daten als "TObject" speichern kann. Ein StringGrid. In diesem StringGrid speichere ich pro Zeile die Nutzinformationen in StringGrid.Objects[0, iRow]. Zum Speichern verwende ich einen eigenen Typ "TGridObject". Nun möchte ich eine allgemeingültige Funktion haben, mit welcher ich im StringGrid einen Hint anzeigen kann. Damit diese Funktion auch auf anderen Grids funktioniert definiere ich ein Interface "IGridInfo", welches mir die Funktion "GetVal(const iCol : Integer) : String;" bereit stellen soll. Die Idee ist, dass die "AutoGridHint"-Funktion den String, welcher angezeigt werden kann über diese Funktion erhällt. Das Objekt muss dann natürlich von diesem Interface erben und die Funktion umsetzen. Definition vom Interface in der Tools-Unit:
Delphi-Quellcode:
Definition des GridObjects in der Unit mit dem Form:
type
IGridInfo = interface(IInterface) ['{675C1022-0376-4583-AF24-8FAA2D008139}'] Function GetVal(const iCol : Integer) : String; end;
Delphi-Quellcode:
Das Grid (sgDaten) wird dann irgendwie irgendwann gefüllt und in Spalte "0" wird das Objekt gespeichert.
type
TGridObject = class(TInterfacedObject, IGridInfo) private FRow : Integer; FSomeText : String; FSomeMore : String; public Function GetVal(const iCol : Integer) : String; Constructor Create(const iRow : Integer; const sText1 : String; const sText2 : String); end;
Delphi-Quellcode:
GetVal(1) soll hierbei FSomeText und GetVal(2) soll FSomeMore zurück geben.
currObj := TGridObject.Create(iRow, 'bla', 'blub');
sgDaten.Objects[0, iRow] := currObj; sgDaten.Cells[1, iRow] := currObj.GetVal(1); In MouseMove vom Grid werden die Koordinaten umgerechnet und an die tolle Methode übergeben:
Delphi-Quellcode:
Bisher bin ich bei solchen Sachen dann hingegangen und habe folgendes gemacht (was auch toll funktioniert):
procedure TfrmMain.sgDatenMouseMove(
Sender : TObject; Shift : TShiftState; X : Integer; Y : Integer ); var ACol : Integer; ARow : Integer; begin inherited; sgDaten.MouseToCell(x, y, ACol, ARow); AutoGridHint(sgDaten, ACol, ARow); End;
Delphi-Quellcode:
Jetzt wollte ich das aber ja, wie oben schon erkennbar, über eine zentrale Methode laufen lassen.
procedure TfrmMain.sgDatenMouseMove(
Sender : TObject; Shift : TShiftState; X : Integer; Y : Integer ); var ACol : Integer; ARow : Integer; GridObj : TGridObject; sHint : String; begin inherited; sgDaten.MouseToCell(x, y, ACol, ARow); if (sgDaten.Objects[0, ARow] <> nil) AND (sgDaten.Objects[0, ARow] IS TGridObject) then Begin GridObj := sgDaten.Objects[0, ARow] AS TGridObject; sHint := GridObj.GetVal(ACol); if (sgDaten.Hint <> sHint) then Begin Application.CancelHint(); sgDaten.Hint := sHint; End; End; end; In den Tools hatte ich zuletzt dieses hier:
Delphi-Quellcode:
Anstelle vom "IS"-Operator für Objekte soll man bei Interfaces offensichtlich
Procedure AutoGridHint(
sgCurr : TStringGrid; const iCol : Integer; const iRow : Integer ); var GridObj : IGridInfo; sHint : String; Begin if (sgCurr.Objects[0, iRow] <> nil) AND (Supports(sgCurr.Objects[0, iRow], IGridInfo)) then Begin GridObj := IGridInfo(sgCurr.Objects[0, iRow]); // <- Nope sHint := GridObj.GetVal(iCol); if (sgCurr.Hint <> sHint) then Begin Application.CancelHint(); sgCurr.Hint := sHint; End; End; End; "Supports" aus den SysUtils nehmen. Aber egal ob ich versuche den Cast zu erzwingen "IGridInfo(...)" oder vorsichtig zu erfragen "X AS IGridInfo", der Compiler will das nicht. Das unterliegende Objekt erbt ja das Interface, aber diese vorgehensweise ist in Delphi wohl nicht vorgesehen. Ich befürchte auch, dass "Supports" prüft, ob die Klasse "TObject" das Interface "IGridInfo" erbt und nicht das Objekt, was tatsächlich gespeichert ist, denn die Funktion liefert mir "False". "IS" und "AS", wie ich das von Klassen kenne läuft hier nicht, aber warum und wie löst man sowas dann? Frage zusammengefasst also: Wenn ich eine Klasse A [TGridObject] erstelle, welche vom Interface X [IGridInfo] erbt und ich ein Objekt A1 dieser Klasse A erzeuge und in einer Variable V1 speichere, welche vom Typ (Klasse) B [TObject] ist (wobei die Klasse A von Klasse B erbt), wie kann ich auf die Funktionen des Interface X [IGridInfo] zugreifen, wenn ich als Übergabe nur eine Variable V1 habe? Oder vielleicht noch ein kurzes (unrealistisches!) Beispiel mit dem ersten Interface, was ich in SysUtils gefunden habe (damit ist dann alles in einer Funktion):
Delphi-Quellcode:
Und wehe es kommt einer und sagt "mach doch einfach >v1.BeginRead<"! :lol:
Procedure Test();
var v1 : TSimpleRWSync; v2 : TObject; v3 : IReadWriteSync; Begin // Erstelle Objekt vom Typ 1 v1 := TSimpleRWSync.Create(); // Speicher in Oberklasse: v2 := v1; // Mach irgendwas, um aus v2 das Interface zu bekommen: v3 := Irgendwas_IReadWriteSync(v2); // Arebite mit den Methoden des Interface: v3.BeginRead(); v3.EndRead(); End; Ich hoffe jemand hat da eine Idee zu. Schonmal vielen Dank alleine für die Zeit für's lesen! Liebe Grüße Incocnito |
AW: TObject As Interface
Ohne groß nachzudenken würde ich es so versuchen:
Delphi-Quellcode:
[edit] Vermutlich wäre es aber sachdienlicher, TGridInfo nicht von TInterfacedObject, sondern von TInterfacedPersistent abzuleiten, um die Referenzzählung und damit ein unbeabsichtigtes Freigeben zu umgehen. [/edit]
Procedure AutoGridHint(
sgCurr : TStringGrid; const iCol : Integer; const iRow : Integer ); var GridObj : IGridInfo; sHint : String; Begin if Assigned(sgCurr.Objects[0, iRow]) AND Supports(sgCurr.Objects[0, iRow], IGridInfo, GridObj) then Begin //GridObj := IGridInfo(sgCurr.Objects[0, iRow]); // <- Nope sHint := GridObj.GetVal(iCol); if (sgCurr.Hint <> sHint) then Begin Application.CancelHint(); sgCurr.Hint := sHint; End; End; End; |
AW: TObject As Interface
Danke für die schnelle Antwort!
Respekt, dass du das so schnell raus hattest! Mit - Assigned (aber ich glaube das tut nichts zur Sache) - Supports + Parameter - TInterfacedPersistent läufts exakt, wie es soll! Liebe Grüße Incocnito |
AW: TObject As Interface
Zitat:
Wenn Du Objekt- und Interface-Referenzen mischen willst brauchst Du eine Basisklasse, die IInterface ohne reference counting implementiert. Z. B. die hier:
Delphi-Quellcode:
TPersistent ist auch geeignet, diese Klasse hat ebenfalls eine IInterface-Implementierung ohne reference counting, schleppt aber mehr Ballast mit.
{! == BaseNonRefcountIntfObjU ===========================================
<summary> This unit provides a base class with a non-reference counted implementation of IUnknown/IInterface.</summary> <author>Dr. Peter Below</author> <history> Version 1.0 created 2002-03-28<p> Version 1.0 created 2009-03-22, changed docs to XML, checked for Unicode issues.<p> Version 2.0 created 2016-08-05, renamed to scoped name, adjusted uses clauses.<p> Last modified 2016-08-05<p> </history> <remarks></remarks> <copyright>Copyright 2009 by Dr. Peter Below</copyright> <licence> The code in this unit is released to the public domain without restrictions for use or redistribution. Just leave the copyright note above intact. The code carries no warranties whatsoever, use at your own risk!</licence> =======================================================================} unit PB.BaseNonRefcountIntfObjU; interface type {! <summary> Derive classes that need a non-reference counted IInterface implementation from this class.</summary> } TNonRefcountInterfacedObject = class(TObject, IInterface) protected {! <summary> Try to obtain an interface from this object.</summary> <returns>S_OK if the interface could be found, E_NOINTERFACE otherwise.</returns> <param name="IID">identifies the interface to get, can be a GUID or an interface type with a GUID.</param> <param name="Obj">receives the found interfaces reference.</param> } function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; {! <summary> Does nothing and always returns -1. </summary> } function _AddRef: Integer; stdcall; {! <summary> Does nothing and always returns -1. </summary> } function _Release: Integer; stdcall; end; implementation function TNonRefcountInterfacedObject.QueryInterface( const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE end; function TNonRefcountInterfacedObject._AddRef: Integer; begin Result := -1 // -1 indicates no reference counting is taking place end; function TNonRefcountInterfacedObject._Release: Integer; begin Result := -1 // -1 indicates no reference counting is taking place end; end. Die Supports-Funktion aus System.Sysutils ist die bevorzugte Methode, um aus einer objektreferenz eine Interface-Referenz zu extrahieren. Ein "as" typecast funktioniert normalerweise auch, dafür muß der Interface-Type aber eine GUID haben. |
AW: TObject As Interface
Wenn ich mich recht erinnere, funktioniert auch mit Interfaces das IS. Und damit es funktioniert, muss man bei der Interface-Deklaration eine GUID angeben. Und ich glaube, dasselbe gilt auch für Supports.
(Das ist jetzt nur so dahin getippert, ohne Deinen Code genauer angeschaut zu haben.) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:39 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 by Thomas Breitkreuz