![]() |
Polymorphie mit eigenen Frames: TabOrder nicht gefunden
Liste der Anhänge anzeigen (Anzahl: 1)
Moin moin... Bin neu hier und hab auch gleich eine Frage. :mrgreen: :angle2:
Achtung, wird etwas länger, aber der größte Teil des Quellcodes zeigt nur den Kontext des Problems und kann schnell überflogen werden. Also, in meinem Programm erstelle ich dynamisch zur Laufzeit Seiten für ein PageControl. Diese Seiten sehen folgendermaßen aus:
Delphi-Quellcode:
Der ContentFrame wird von verschiedenen Klassen, die von TSheetFrame abgeleitet wurden, instanziiert, z.B. so:
type
TFileSheet = Class(TTabSheet) private FileName: String; Modified: Boolean; Mode: TGenerationMode; ID: integer; AddRule: TAdditionalRules; ContentFrame: TSheetFrame; end;
Delphi-Quellcode:
Ein TSheetFrame ist übrigens lediglich eine Interface-Klasse folgender Gestalt:
case Mode of
SimpleMode: begin SheetFrame:=TFrameSimpleMode.Create(FileSheet[c]); InitSheetFrame(SheetFrame as TFrameSimpleMode); end; AdvancedMode: begin SheetFrame:=TFrameAdvMode.Create(FileSheet[c]); InitSheetFrame(SheetFrame as TFrameAdvMode); end; // usw... else SheetFrame:=NIL; end; {of case} FileSheet[c].ContentFrame:=SheetFrame; SheetFrame.Parent:=FileSheet[c];
Delphi-Quellcode:
Die Polymorphie ist eigentlich nur dafür gut, damit ich später, wenn man zur Laufzeit die Sprache umstellt, folgendes schreiben kann:
type
TSheetFrame = Class(TFrame) public procedure RefreshLanguage; virtual; abstract; end;
Delphi-Quellcode:
So, jetzt das eigentlich Problem:
for i:=0 to PageControlMode.PageCount-1 do
begin FileSheet[i].ContentFrame.RefreshLanguage; end; Damit die Polymorphie funktioniert, muss ich ja meine Frames von TSheetFrame statt von TFrame ableiten. Also habe ich einfach überall in dem automatisch generierten Code die Klassen-Deklaration entsprechend umgeändert. Vorher:
Delphi-Quellcode:
Nachher:
type
TFrameSimpleMode = class(TFrame) ComboBoxTemp: TComboBox; LabelTemplate: TLabel; private { Private-Deklarationen } public { Public-Deklarationen } procedure RefreshLanguage; override; end;
Delphi-Quellcode:
Alles funktioniert wie es soll.
type
TFrameSimpleMode = class(TSheetFrame) ComboBoxTemp: TComboBox; LabelTemplate: TLabel; private { Private-Deklarationen } public { Public-Deklarationen } procedure RefreshLanguage; override; end; Aber: Nachdem ich das Projekt geschlossen hatte, konnte ich mir nach dem Öffnen nicht mehr die Frames (den Code oder das Form) anschauen, ohne die angehängte Fehlermeldung präsentiert zu bekommen. Danach lässt sich das Programm nicht mehr compilieren! Wenn ich mir aber nach dem Öffnen kein Frame anschaue, dann lässt sich das Programm aber normal compilieren und starten. Offensichtlich kommt Delphi irgendwie nicht damit klar, dass ich an den "von ihm" kreierten Frames rumgefuscht habe. Ich würde jetzt aber gerne wissen, was genau das Problem ist. Wie würde man das richtig machen (mit Polymorphie). Ich habe das Problem inzwischen ohne Polymorphie -mit case und typecasts- gelöst. Ich möchte aber gerne wissen, warum es nicht so ging wie ich es versuchte. PS: Der erste, der eine gute Antwort abliefert, kriegt ein virtuelles Bier spendiert. :mrgreen: :cheers: |
Re: Polymorphie mit eigenen Frames: TabOrder nicht gefunden
*push*
|
Re: Polymorphie mit eigenen Frames: TabOrder nicht gefunden
Hallo Neg,
weil ich nur der erste sein möchte, der Dir hier antwortet ("Beer!"), möchte ich Dich an dieser Stelle lediglich auf Interfaces hinweisen. Eine Lösung der Art
Delphi-Quellcode:
sollte darüber hinaus die Erweiturung des Konzepts auf andere Klassen (zB TForm) ermöglichen, die nicht von einer abstrakten Oberklasse erben, ohne das der Client (Aufrufer) angepasst werden muss:
type
IMyInterface = interface ['YourGUID'] procedure RefreshLanguage; end; TMyFrame = class(TFrame, IMyInterface) protected procedure RefreshLanguage; end; TForm1 = class(TForm, IMyInterface) protected procedure RefreshLangauge; end;
Delphi-Quellcode:
Ich empfehle Dir weiterhin eine Registratur aller anpassbaren Elemente (zB in Form eines
var
myInterface: IMyInterface; myFrame: TMyFrame; begin myFrame:= TMyFrame.Create(AForm); with myFrame do //... // use instances' interface myInterface:= myFrame; myInterface.RefreshLanguage; myInterface:= AForm; myInterface.RefreshLanguage; // syntactical suggar (myFrame as IMyInterface).RefreshLanguage; (AForm as IMyInterface).RefreshLanguage; ![]()
Delphi-Quellcode:
um später zB mit dem Aufruf
constructor TMyFrame.Create(..);
begin inherited; TLanguageSingelton.Instance.Register(Self); end;
Delphi-Quellcode:
alle zu aktualisierenen Exemplare zu iterieren unabhängig davon, auf welchen Controls sie sich tatsächlich befinden...
TLanguageSingelton.Instance.RefreshLanguage;
Falls Du später mehrere solcher Funktionalitäten zur Verfügung stellen solltest, könnte dieser Ansatz jedoch schnell in sog "god-interfaces" ausarten. Für diesen Fall könnte man lieber ein Delegations-Objekt oder die simplifizierte Delphi-Variante, ein Ereignis, registrieren, dass das alleinige Wissen über die durchzuführenden Aktionen hat... |
Re: Polymorphie mit eigenen Frames: TabOrder nicht gefunden
Aha. Das sieht interessant aus.
Sehe ich das richtig, dass TMyFrame = class(TFrame, IMyInterface) im Grunde so etwas wie eine Mehrfachvererbung ist, nur dass die zweite Klasse eben keine "richtige Klasse", sondern nur ein Interface ist - so, als würde ich z.B. in C++ eine Klasse als abstrakt deklarieren und ihre Methoden nicht implementieren, also nur Siganturen liefern (Interface-Klasse)? |
Re: Polymorphie mit eigenen Frames: TabOrder nicht gefunden
Das implementieren eines Interfaces (IMyInterface) kann man in C++ tatsächlich mit dem Merfacherben einer puren abstrakten Klasse (IMyInterface) vergleichen, allerdings wäre diese pure abstrakte Klasse wiederum von der abstrakten Klasse IInterface abgeleitet, die drei abstrakte Methoden (_AddRef, _Release und QueryInterface) einführt und den Zuweisungsoperator operator = () in der Form überlädt, dass eine Zuweisung eines Objekts (!=null eq <>nil) die vom Erben zu implementiernde Methode _AddRef aufruft und das aufheben einer Referenz (bzw Zuweisen von nil) die vom Erben zu implementiernde Methode _Release aufruft (Referenzzählung).
Der Compiler sorgt darüber hinaus dafür, dass diese "Zuweisung mit nil" (durch Try..Finally geschützt) auch beim Verlassen des Gültigkeitbereichs durchgeführt wird, ähnlich dem C++ Konzept der SmartPointer (tatsächlich gibt es mit TInterfacedObject bereits ein Objekt, dass sich "selbst freigibt"). ![]() Eine kleine Anmerkung zur beschriebenen Lösung mit TMyFrame (s.o.): Die Klasse TComponent implementiert bereits die von IInterface (bei Deinem D5 heißt es IUnknown) geforderten Methoden und führt zur Referenzzählung (im Normalfall) eine Dummyoperation aus. |
Re: Polymorphie mit eigenen Frames: TabOrder nicht gefunden
Baue eine separate Unit die du in einem DesignTime Package installierst. In dieser Unit sollte inetwa folgendes stehen:
Delphi-Quellcode:
Ab D6 oder D7 musst du bei der Delphi IDE einen Klassen-Editor registrieren.
unit RegMySheets;
interface uses DesignIntf, DesignEditors; procedure Register; implementation uses ....; procedure Register; begin RegisterCustomModule(TSheetFrame, nil); end; Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:28 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