![]() |
EntwZeit - Subkomponente löschen - Exception wird ausgelöst
Ich weiß gar nicht, ob ich in diesem Forum trotz Anmeldung schon einen Beitrag geschrieben hatte, deshalb noch mal Hallo an das Forum. :hello:
Ich setzte mich gerade das erste Mal mit der Entwicklung eigener Komponenten auseinander. Die Grundlage und Installation einer neuen Komponente läuft fehlerfrei. Nun bin ich dabei, Eigenschaften für Subkomponenten zu implementieren. Diese sind derzeit existierende native Komponenten von D7, z. B. eine ComboBox. Relevanter Code ...
Delphi-Quellcode:
Nun habe ich folgendes Problem: Wenn ich eine ComboBox in meine Anwendung ziehe und diese meiner Komponente zuweise, dann kann ich die ComboBox nicht löschen, ohne diese in meiner Komponente vorher abzuwählen. Bleibt die ComboBox in meiner Komponente zugewiesen und ich lösche sie, wird eine Exception ausgelöst. Anschließend kann ich nicht mehr auf meine Komponente zugreifen, da weiterhin eine Exception ausgelöst wird.
unit DkComponent;
interface uses Classes, StdCtrls; type TDkComponent = class( TComponent ) private FComboBox : TComboBox; published property ComboBox : TComboBox read FComboBox write FComboBox; end; procedure Register ( ); implementation procedure Register ( ); begin RegisterComponents( 'Test Components', [ TDkComponent ] ); end; end. Ich habe mir die Quellen von TForm und deren Vorfahrenreihe angesehen, um herauszufinden, wie es dort mit dem Popup gelöst wurde. Aber da ist nix dabei, was mir helfen könnte. Ich finde keine Codes, die das Löschen direkt überprüfen, oder ähnliches. |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Wie weist du zu?
|
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Ich habe beide Komponenten, meine eigene und die ComboBox, auf das Formular gezogen und weise die ComboBox meiner Komponente im Objekt-Inspektor zu.
Edit: Normal per DropDown der Eigenschaft ComboBox im Obj.-Inspektor. Edit 2: Ich habe den Quellcode im ersten Thread erweitert. Hatte die Registrierung der Komponente vorerst weggelassen. |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Hier nochmal die Exception, wenn ich die ComboBox lösche:
Zitat:
Delphi-Quellcode:
Das war auch ein Fehlversuch. Resultat ist, dass er weiterhin die Exception beim Löschen auslöst. Nun kommt dazu, dass er beim Start der Applikation einen "EReadError" auslöst.
type
TDkComponent = class( TComponent ) private FComboBox : TComboBox; protected procedure SetComboBox ( pValue : TComboBox ); virtual; published property ComboBox : TComboBox read FComboBox write SetComboBox; end; implementation procedure TDkComponent.SetComboBox ( pValue : TComboBox ); begin Self.FComboBox := pValue; Self.FComboBox.SetSubComponent( True ); end; Zitat:
|
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Du brauchst keinen Setter, musst aber die Methode Notification überschreiben und beim Löschen der Combobox dein Feld auf nil setzen.
|
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Danke Philip für den Tip.
Zum besseren Verständnis schaue ich mir erst mal die geerbte Methode von TComponent an, damit ich weiß, was ich da überhaupt mache. So tief bin ich bisher nie in die Delphi-OO-Materie eingestiegen.
Delphi-Quellcode:
Wenn ich die ComboBox meiner Komponente zuweise, dann wird doch aber nicht wirklich der Owner der ComboBox neu zugewiesen? Dieser wurde ja bereits beim Drop auf das Formular zugewiesen. Das würde bedeuten, dass TDkComponent.Components nicht verändert wird.
procedure TComponent.Notification(AComponent: TComponent;
Operation: TOperation); var I: Integer; begin if (Operation = opRemove) and (AComponent <> nil) then RemoveFreeNotification(AComponent); if FComponents <> nil then begin I := FComponents.Count - 1; while I >= 0 do begin TComponent(FComponents[I]).Notification(AComponent, Operation); Dec(I); if I >= FComponents.Count then I := FComponents.Count - 1; end; end; end; Wenn ich "Notification" richtig deute, bezieht es sich doch aber auf das Löschen einer Komponente aus der Eigenschaft "Components". Wird diese nicht nur für Komponenten verwendet, deren Eigenschaft Owner auf eben jenes TComponent-Objekt referenziert? Außerdem verstehe ich nicht ganz, warum Components in Notification komplett rekursiv freigegeben wird. Entschuldigt bitte, wenn ich jetzt hier im Forum im Grundwissen rumstocher. :oops: Möglich, das ich Dinge falsch verstehe. |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Notification wird immer dann aufgerufen, wenn der Owner deiner Komponente (bei zur Design-Zeit erstellten Komponenten ist dies das Formular) eine neue Unterkomponente erhält oder eine Unterkomponente zerstört wird. Operation ist dabei entweder opInsert oder opRemove und AComponent die Komponente.
In deiner überschriebenen Notification-Methode musst du also prüfen, ob AComponent deine Combobox und Operation opRemove ist, wenn ja, musst du dein Feld auf nil setzen. Schau dir dazu auch mal TControl.Notification an. Zitat:
|
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Delphi-Quellcode:
Jetzt funktioniert das Löschen ohne Exception. Und die geebrte "Notifcation" werde ich mir noch mal ganz in Ruhe ansehen. Man kann ja nur daraus lernen.
unit DkComponent;
interface uses Classes, StdCtrls; type TDkComponent = class( TComponent ) private FComboBox : TComboBox; protected procedure Notification ( pComponent : TComponent; pOperation : TOperation ); reintroduce; virtual; published property ComboBox : TComboBox read FComboBox write FComboBox; end; procedure Register; implementation procedure Register; begin RegisterComponents( 'Test', [ TDkMailAccount ] ); end; { TDkComponent } procedure TDkComponent.Notification ( pComponent : TComponent; pOperation : TOperation ); begin inherited Notification( pComponent, pOperation ); if ( pOperation = opRemove ) and ( FComboBox <> nil ) and ( pComponent = Self.ComboBox ) then Self.ComboBox := nil; end; end. Wirklich vielen Dank für die Unterstützung. :) |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
:shock: Das dürfte eigentlich nicht funktionieren. Du solltest statt reintroduce override verwenden.
Außerdem kannst du deine If-Abfrage etwas vereinfachen. Gewöhnlich verwendet man für die Eigenschaft den Custom*-Typ. Dadurch wird gewährleistet, dass auch weiterentwickelte Comboboxen benutzt werden können. |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Die hier gepostete Klasse ist nur eine Beispielklasse.
Variante 1 der Doku. Viele meiner Methoden erhalten veränderte Parameterzuweisungen, dann funktioniert "override" nicht mehr. Muss ja identisch sein. Variante 2 der Doku. Ich könnte die Methode umbenennen. Aber das will ich ja nicht, ich will die geerbte ja überschreiben. Variante 3 der Doku. Mir bleibt also nur "reintroduce" um zumindest die Warnung zu verstecken. Allerdings weiß ich nicht, ob ich die überschriebene Methode auch als "virtual" deklarieren muss, oder ob das grundsätzlich von Elternklassen mit vererbt wird. Ansonsten war die ComboBox nur ein Versuchsobjekt. Im Ernstfall hätte ich die Custom* verwendet. Edit: Wegen der If-Abfrage denk ich erstmal selber nach. Ist eine rein logische Geschicht. |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Reintroduce ist nicht das selbe wie override! Denn dann steht in der VMT immer noch die alte Methode TComponent.Notification, und das willst du ja gerade vermeiden. Reintroduce überschreibt eben nicht, wie man schon am Namen sieht.
|
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
If-Struktur geändert.
Ja, ich hatte die If-Struktur einfach von "TControl.Notification" übernommen. Hab endlich auch einen sehr kurzen Text in meinem Handbuch gefunden, wo selbes wie bei TControl Konstrukt beschrieben ist.
Delphi-Quellcode:
Die Komponente, die gelöscht werden soll, kann nicht "nil" sein. Dann wurde sie ja bereits gelöscht.
procedure TDkComponent.Notification
( pComponent : TComponent; pOperation : TOperation ); begin inherited Notification( pComponent, pOperation ); if ( pOperation = opRemove ) and ( pComponent = Self.FComboBox ) then Self.FComboBox := nil; end; Allerdings verstehe ich auch nicht, warum mit der Eigenschaft "ComboBox" anstelle der privaten "FComboBox" gearbeitet wurde. Mein Problem ist aber (in diesem Beispiel nicht), dass ich oft Methoden mit komplett neuen Parametern überschreibe. Meistens sind es die Konstruktoren. Da funktioniert "override" nicht. Aber ich will eben auch keine Methode mit neuem Namen implementieren. Gerade Create sollte auch Create bleiben. Gibt es noch eine 4. Möglichkeit? |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Override ist ein Schlüsselwort, dass nicht ersetzt werden kann. Es gibt keine Alternative dazu.
|
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Aus der Doku:
Delphi-Quellcode:
Allerdings ist die geebrte Methode immer noch verfügbar, also nicht wirklich überschrieben.
T1 = class(TObject)
procedure Test(I: Integer); overload; virtual; end; T2 = class(T1) procedure Test(S: string); reintroduce; overload; end; // ... SomeObject := T2.Create; SomeObject.Test('Hello!'); // calls T2.Test SomeObject.Test(7); // calls T1.Test Kannst Du mir bitte in knappen Worten beschreiben, wozu Methoden versteckt werden müssen? Wenn es nicht zu groß ist das Thema. Ach verdammter Mist! Ich hätte dem Thema der OOP mehr Achtung schenken sollen. :wall: Mir fehlt einfach das nötige Wissen zu grundlegenden Konzepten. Wie ärgerlich, egal in welcher Progr.-Sprache. Werde wohl noch mal Tutorials pauken. :!: |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Beispiel:
Delphi-Quellcode:
Getippt und nicht getestet.
program VirtualMethodsTest;
type TAncestor = class procedure TestMethod; virtual; end; TDescendent = class(TAncestor) procedure TestMethod; override; {testweise durch reintroduce ersetzen} end; procedure TAncestor.TestMethod; begin Writeln('TAncestor.TestMethod'); end; procedure TDescendent.TestMethod; begin Writeln('TDescendent.TestMethod'); end; var Inst: TAncestor; begin Inst := TDescendent.Create; try Inst.TestMethod; finally Inst.Free; end; end. Du wirst einen Unterschied erkennen, wenn du override durch reintroduce ersetzt. |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
OK. Alles klar. Jetzt weiß ich, wo meine Lücke war. Ich hatte den Fall so konkret noch nicht. Ich habe es immer vermieden die Nachfahren-Methoden aus dem Vorfahren heraus aufzurufen.
Ich habe Dein Lernbeispiel mal experimentell erweitert und ... naja, in Worte fassen kann ich es auch nicht. Das habe ich schon versucht. Aber ich habe es klar verstanden.
Delphi-Quellcode:
Alles klar! Ein wirklich interessantes Konstrukt. Die Frage ist nur, ob sowas Sinn macht. Wenn es einen wirklich wichtigen Anwendungsfall dafür gibt (HAHA), so sind Java und Andere im deutlichen Nachteil, da diese alle Methoden nativ als virtuell deklarieren.
program test;
type TA = class procedure Test; virtual; end; TD1 = class( TA ) procedure Test; reintroduce; end; TD2 = class( TA ) procedure Test; override; end; TD3 = class( TD1 ) procedure Test; virtual; end; TD4 = class( TD3 ) procedure Test; override; end; procedure TA.Test; begin WriteLn( 'A' ); end; procedure TD1.Test; begin WriteLn( 'D1' ); end; procedure TD2.Test; begin WriteLn( 'D2' ); end; procedure TD3.Test; begin WriteLn( 'D3' ); end; procedure TD4.Test; begin WriteLn( 'D4' ); end; var Inst1 : TA; Inst2 : TD3; begin Inst1 := TD1.Create; try Inst1.Test; finally Inst1.Free; end; Inst1 := TD2.Create; try Inst1.Test; finally Inst1.Free; end; Inst1 := TD3.Create; try Inst1.Test; finally Inst1.Free; end; Inst1 := TD4.Create; try Inst1.Test; finally Inst1.Free; end; Inst2 := TD3.Create; try Inst2.Test; finally Inst2.Free; end; Inst2 := TD4.Create; try Inst2.Test; finally Inst2.Free; end; end. ![]() Vielen herzlichen Dank für den Codeschnipsel. Der erklärte mir alles. :thumb: Jetzt fällt mir nach 12 Jahren alles wieder ein. Edit: Nun muss ich ja doch meine Methoden umbenennen. Sonst verbau ich mir eine Menge Möglichkeiten. So'n Mist! |
Re: EntwZeit - Subkomponente löschen - Exception wird ausgel
Nachtrag:
Ich habe versucht ein Design-Pattern zu entwerfen, damit ich in die Komponente neue SubKomponenten einbinden kann, ohne jedesmal eine if-Anweisung in die Notification einzubauen, die explizit überprüft, ob Parameter-Komponente "pComponent" = private Komponente ist. Es wurde kein Design-Pattern, sondern ich habe nochmal die existierende If-Anweisung überarbeitet. @Philip Jetzt versteh ich, was Du eigentlich mit if-Anweisung überarbeiten meintest.
Delphi-Quellcode:
So, nun kann man alle möglichen Subkomponenten in die Komponente einbauen und diese im Obj.-Inspektor wieder löschen.
procedure TDkMailAccount.Notification
( pComponent : TComponent; pOperation : TOperation ); begin inherited Notification( pComponent, pOperation ); if pOperation = opRemove then pComponent := nil; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:29 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