![]() |
Sub-Komponenten serialisieren
Hallo, ich habe folgende Konstellation:
Delphi-Quellcode:
das will ich speichern und vor allem laden:
type
TBaseFormElementManager = class abstract(TComponent) protected FControl: TControl; //<--- der da FNaturalDimensions: TDRect; MouseUpEvents: TEventList; MouseDownEvents: TEventList; MouseMoveEvents: TEventList; public procedure SetElement(Value: TControl); virtual; function GetElement: TControl; virtual; procedure SetLeftMm(Value: Double); procedure SetTopMm(Value: Double); procedure SetWidthMm(Value: Double); procedure SetHeightMm(Value: Double); procedure SetLeftPx(Value: Integer); //<--- hier procedure SetTopPx(Value: Integer); procedure SetWidthPx(Value: Integer); procedure SetHeightPx(Value: Integer);
Delphi-Quellcode:
procedure TFormElementSupplier.Save(FileName: string);
var i,size: Integer; m: TBaseFormElementManager; ms,msc: TMemoryStream; begin ms := TMemoryStream.Create; msc := TMemoryStream.Create; try for i := 0 to Elements.Count -1 do begin ms.Size := 0; ms.WriteComponent(Elements[i]); ms.Position := 0; size := ms.Size; msc.Write(size,SizeOf(size)); msc.CopyFrom(ms, size); end; msc.Position := 0; msc.SaveToFile(FileName); finally ms.Free; msc.Free; end; end;
Delphi-Quellcode:
Im ReadComponent wird aber gleich ins SetLeftPx gesprungen, was ich auch nachvollziehen kann:
procedure TFormElementSupplier.Load(FileName: string);
var c: TComponent; ms,msc: TMemoryStream; size: Integer; begin ms := TMemoryStream.Create; msc := TMemoryStream.Create; try ms.LoadFromFile(FileName); while ms.Position < ms.Size do begin ms.Read(size,SizeOf(size)); msc.Clear; msc.CopyFrom(ms,size); msc.Position := 0; c := nil; c := msc.ReadComponent(nil); //<--- HIER Elements.Add(c as TBaseFormElementManager); end; finally ms.Free; msc.Free; end; end;
Delphi-Quellcode:
Wo dann FControl auf nil ausgewertet wird und die Exception kommt.
procedure TBaseFormElementManager.SetLeftPx(Value: Integer);
begin if Assigned(FControl) then FControl.Left := Value else raise EElementNotCreated.Create('No Element Created yet.'); end; Wie bringe ich das ganze System dazu, dass das Control ordentlich zugewiesen wird? Bzw. überhaupt mitgespeichert, ich weiß ja nicht, ob das überhaupt passiert. Ich sollte vielleicht noch einmal erwähnen, dass TBaseFormElementManager nie instanziiert wird, sondern es sich immer um nachfahren handelt. EDIT: hab inzwischen "Setsubcomponent" gefunden... ändert nix... :gruebel: |
Re: Sub-Komponenten serialisieren
Niemand einen Tipp für mich?
|
Re: Sub-Komponenten serialisieren
Zitat:
|
Re: Sub-Komponenten serialisieren
published property ist es deswegen, weil ich sie veröffentlichen will ;)
Ich will es im jedi-runtime-OI drin haben(TJvInspector, imo), allerdings nicht das komplette Control, sondern eben nur ausgewählte über diesen Umweg. Ich werde wohl einfach noch irgendwie eine Weiche einbauen, die mir sagt, dass gerade deserialisiert wird. dann muss ich nicht die exception werfen... |
Re: Sub-Komponenten serialisieren
Hab ich doch glatt vergessen, dass in Delphi OI-Binding und Serialization dämlicherweise verbunden sind :duck: .
Da du also nicht die Serialisierung von Left verhindern kannst, musst du - wie du schon selbst erkannt hast - stattdessen die Property beim Deserialisieren ignorieren -> TComponentState.csReading. |
Re: Sub-Komponenten serialisieren
Das Problem ist IMHO, dass du - wo wies aussieht das Control zur Designtime erstellst und dann der property zuweist. Wenn das Objekt dann wieder deserialisiert wird, is der Pointer noch nil ==> AV.
Du müsstest also sicherstellen, dass zum Zeitpunkt des Zugriffs - am besten schon im Konstruktor - der Property n Control zugewiesen wurde. Also entweder im Konstruktor das Control zuweisen oder gleich dort erstellen... mfg Christian |
Re: Sub-Komponenten serialisieren
Zitat:
Zitat:
|
Re: Sub-Komponenten serialisieren
Zitat:
Zitat:
Spaß beiseite: IMHO wird durch ReadComponent nur das serialisierte Objekt *ohne* Unterobjekte created. Für das Createn der Unterobjekte is das Objekt selbst verantwortlich. Wenn also das Control nicht im Konstruktor erstellt wird und auch sonst nirgendwo, dann produziert ReadComponent eine Exception, weil es ein bereits erstelltes Objekt erwartet, aber nicht findet... mfg Christian |
Re: Sub-Komponenten serialisieren
SetSubComponent sollte doch eigentlich genau das machen...
Wie bereits gesagt, ich werde jetzt eine globale variable "IsUnserializing" einführen, die in der initialization auf false, beim laden auf true setzen und das ganze entsprechend behandeln. |
Re: Sub-Komponenten serialisieren
Zitat:
Zitat:
mfg Christian |
Re: Sub-Komponenten serialisieren
lol?
Serialisierung hat mit Deserialisierung nix zu tun? Das ist doch... bescheuert... aber leider hast du anscheinend recht. Also muss ich die doch extra speichern :wall: Pfff... nervig... Ich will .Net :cry: |
Re: Sub-Komponenten serialisieren
Zitat:
Zitat:
Zitat:
mfg Christian P.S.: ggf. könnte es auch Helfen zu wissen, was genau du amchen willst. Wird das Control von deiner Komponente erstellt? Übergibst du n Pointer zur Laufzeit...? |
Re: Sub-Komponenten serialisieren
OK... ich werd mich malö noch ein bisschen ausbreiten, da jetzt ein anderes Problem auftaucht.
.Net? Also unter .Net 2.0 mit VC# Express muss ich nur [(Serializable)] als attribut zu meiner Klasse hinzufügen und kann das ganze mit z.B. einem BinarySerializer (oder so ähnlich, wie die Klasse genau heisst, weiß ich grade nicht) serialisieren und genau so einfach wieder deserialisieren. :) Und hier hab ich jetzt das problem, dass ich einen Owner brauche. Und zwar läuft das ganze so ab: - Ich erstelle das Managerobjekt (über einen Index in einer Klassenliste; ich weiß nicht mehr, als dass es von einer Basisklase abstammt) - Ich rufe die Methode CreateElement des Managerobjektes auf, dann wird ein Control erstellt, mit dem Owner(!) auf dem Managerobjekt. Dann serialisiere ich sowohl managerobjekt als auch Control (einzeln) und deserialisiere das auch wieder. Dabei geht der owner verloren - den ich aber unbedingt brauche. Und den ich nciht wieder zuweisen kann. Ich bräuchte also eine Lösung, die sowohl managerobjekt als auch Control kompakt serialisiert und wieder deserialisiert. |
Re: Sub-Komponenten serialisieren
Ich hoffe ich hab dich richtig verstanden. Versuch mal das(wenn du das noch nicht gemacht hast):
Delphi-Quellcode:
Du könntest dir auch mal die erzeugte Datei angucken. Dann merkt man zuerst mal obs Serialisieren richtig geklappt hat...
//Pseudocode:
procedure Start; var ManagerObj: TManager; begin ManagerObj := TButtonManager.Create; // ManagerObjekt erzeugen dabei wird automatisch ein Button erstellt Serialize(ManagerObj); ... ManagerObj.Free; // Manager und Button werden freigegeben ... DeSerialize(ManagerObj); end; constructor TButtonManager.Create; begin inherited Create; // FButton is n privates Feld Button eine publishes Property FButton := TButton.Ceate(self); // owner zuweisen end; procedure Serialize(AManager: TManager); begin ... FileStream.WriteComponent(AManager); // ggf. könnte hier n TypeCast erforderlich sein, dass die RTTI weiß, dass es sich um einen TButtonManager handelt. Bin mir da aber nicht sicher(ich glaubs aber eigentlich nicht). Kenn mich dazu mit RTII noch zu wenig aus ... end; procedure DeSerialize(out AManager: TManager); begin ... FileStream.ReadComponent(AManager); ... end; mfg Christian |
Re: Sub-Komponenten serialisieren
Naja... ich hatte das so ungefähr schon mal. Es sieht so aus:
1. Ich serialisiere nur den Manager -> dann bekommt der Manager keinen Pointer auf das Control, und ich auch nicht 2. Ich serialisiere beides getrennt und weise danach alles wieder zu -> Ich kann den Owner des Controls nicht zuweisen |
Re: Sub-Komponenten serialisieren
Zitat:
mfg Christian P.S.: Hhast du dir mal die serialisierte Klasse als Datei angeguckt? |
Re: Sub-Komponenten serialisieren
Ja, ich habs mir angesehen....
sieht eigentlich ganz gut aus... Ich werd das jetzt (mal wieder^^) umstellen, so dass nur der Manager gespeichert wird, und dann mal gründlich debuggen, vielleicht liegts ja ganz woanders. EDIT: ah ja richtig... entsprechende property hab ich nicht... :gruebel: EDIT: jetzt kommt "ungültiger pfad für eigenschaft" :shock: was ist das denn? EDIT: EReadError wollte ich sagen. hmm... "formulardatei beschädigt" sagt die OH.. soso... kann ich nix von sehen... EDIT: :shock: Das muss der auslöser sein:
Delphi-Quellcode:
aber das kann ja gar nicht sein... und in die classes.pas kann ich natürlich keinen haltepunkt setzen...
if not (PropValue is TPersistent) then PropPathError;
|
Re: Sub-Komponenten serialisieren
Zitat:
Zitat:
Zitat:
Zitat:
mfg Christian |
Re: Sub-Komponenten serialisieren
öhm.... ich muss das im konstruktor erstellen?! ich dachte, der zweck vom deserialisieren ist, dass mans eben nicht erstellt.... :stupid:
hab das mal geändert... und es hat sich nix geändert^^ Aber nach DFM sieht das nicht aus :gruebel:
Code:
‘ TPF0
TFormPanel Control.Left¨ Control.Topš Control.WidthControl.HeightControl.TabOrder LeftPx¨ TopPxš HeightPxWidthPx |
Re: Sub-Komponenten serialisieren
Zitat:
- Der entsprechende Konstruktor wird aufgerufen - die published Properties werden einzeln aus der Datei geparst und per RTTI dem gerade erstellten Objekt zugewiesen. Was aber passiert, wenn das Unterobjekt(dein Control) nicht im Konstruktor erstellt wird? Richtig es gibt ne exception, weil kein weiterer Konstruktor mehr aufgerufen wird. Warum is das aber so? Angenommen es würde wirklich der Konstruktor des Unterobjekts aufgerufen werden. Dann wird dieses neu erstellt. Angenommen du hast sowas im Konstruktor deiner manager-Klasse:
Delphi-Quellcode:
Und dann such mal den Fehler, wenn du dich wunderst, dass es beim Zugriff auf AndererPointer ne AV gibt...
constructor TButtonManager.Create;
begin inherited Create; FButton := TButton.Create; AndererPointer := FButton; ... end; Zitat:
![]() ![]() mfg Christian |
Re: Sub-Komponenten serialisieren
soo... hab jetzt das text-dfm:
Code:
das ist das, was geschrieben werden sollte. ich paste jetzt einfach noch mal meinen code:
object TPanel
Left = 16 Top = 68 Width = 207 Height = 186 TabOrder = 0 end
Delphi-Quellcode:
Nicht, weil ich zu faul bin zum debuggen, sondern weil ich einfach schon alles versucht habe. "knallt hier" ist markiert in der load-procedure... :cry:
procedure TFormElementSupplier.Load(FileName: string; Parent: TWinControl; Add: Boolean);
var Manager: TBaseFormElementManager; ManagerClass: TBaseFormElementManagerClass; ms,msc: TMemoryStream; size: Integer; Index: Integer; begin IsUnSerializing := True; if not Add then Elements.Clear; ms := TMemoryStream.Create; msc := TMemoryStream.Create; try ms.LoadFromFile(FileName); ms.Position := 0; while ms.Position < ms.Size do begin //read class and size of element ms.Read(ManagerClass,sizeof(ManagerClass)); ms.Read(size,SizeOf(size)); //copy element into temporary stream to isolate it msc.Clear; msc.CopyFrom(ms,size); //create manager Manager := ManagerClass.Create; //create element Manager.FControl := ManagerClass.ElementClass.Create(Manager); //unserialize element msc.ReadComponent(Manager.FControl); //<--- knallt hier... "Stream-Lesefehler" Manager.InitElement(Parent); end; finally ms.Free; msc.Free; end; IsUnSerializing := False; end; procedure TFormElementSupplier.Save(FileName: string); var i,size: Integer; ms,msc,textstream: TMemoryStream; ManagerClass: TClass; s: string; begin ms := TMemoryStream.Create; msc := TMemoryStream.Create; textstream := TMemoryStream.Create; try for i := 0 to Elements.Count -1 do begin //write the control msc.Clear; msc.WriteComponent(Elements[i].FControl); msc.Position := 0; size := msc.Size; ObjectBinaryToText(msc,textstream); msc.Position := 0; //write the manager's class ManagerClass := Elements[i].ClassType; ms.Write(ManagerClass, SizeOf(ManagerClass)); //write the size of the control ms.Write(size,SizeOf(size)); //write the control ms.CopyFrom(msc, msc.Size); end; ms.Position := 0; ms.SaveToFile(FileName); textstream.SaveToFile(Filename + 'txt'); finally ms.Free; msc.Free; textstream.Free; end; end; |
Re: Sub-Komponenten serialisieren
Nur ne Vermutung: Vor dem ReadComponent fehlt evtl. n Position := 0;
BTW:
Delphi-Quellcode:
Du greifst doch nicht etwa von außen auf ein Feld zu oder? :?
Manager.FControl
mfg Christian |
Re: Sub-Komponenten serialisieren
Hi jungs,
als ich das hier gelesen habe hab ich mich daran erinnert, dass ich ähnliches auch mal am Wickel hatte. das aber unter D5. Bei mir war es so, dass beim Lesen der Serialisierung die Instanz der Komponente existieren mußte. Also bei nil ging es sowiso in die Hose. es reichte aus einfach erst mal ein Create auszuführen. Ich geb euch hier mal meinen code für das Schreiben und Lesen der Serialisierung. Ich hoffe es hilft. Bei mir war es dann eigentlich kein Problem mehr. Schreiben:
Delphi-Quellcode:
Lesen:
procedure TSercheThread.WriteListToFile;
var Stream : TFileStream; begin IF not Assigned(FMahnListView) then Exit; Stream := TFileStream.Create(MahnFileName, fmCreate or fmShareDenyNone); try Stream.WriteComponent(FMahnListView); finally Stream.Free; end; end;
Delphi-Quellcode:
Das war dann auch wirklich ein TListView. Ob das alles so mit TControl funzt wage ich zu bezweifeln. Ich hoffe ich konnte euch einen Hinweis geben der hilft (bin grad knapp in der Zeit und habe diesen Thread nur diagonal gelesen).
procedure TSercheThread.ReadListFromFile;
var Stream : TFileStream; begin IF not Assigned(FMahnListView) then Exit; IF not FileExists(ExtractFilePath(Application.ExeName) + MahnFileName) then Stream := TFileStream.Create(MahnFileName, fmCreate or fmShareDenyNone) else Stream := TFileStream.Create(MahnFileName, fmOpenReadWrite or fmShareDenyNone); try IF Stream.Size = 0 then Exit; FMahnListView := TListView(Stream.ReadComponent(FMahnListView)); finally Stream.Free; end; end; gruß oki |
Re: Sub-Komponenten serialisieren
Hmmm...
Zitat:
Zitat:
|
Re: Sub-Komponenten serialisieren
Zitat:
![]() mfg Christian |
Re: Sub-Komponenten serialisieren
Properties? Ja, da muss ich nur das "F" aus dem aufrufenden Source entfernen :mrgreen:
|
Re: Sub-Komponenten serialisieren
Zitat:
mfg Christian |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:18 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