Delphi-PRAXiS
Seite 1 von 3  1 23      

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 Sub-Komponenten serialisieren (https://www.delphipraxis.net/76134-sub-komponenten-serialisieren.html)

DGL-luke 30. Aug 2006 13:51


Sub-Komponenten serialisieren
 
Hallo, ich habe folgende Konstellation:

Delphi-Quellcode:
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);
das will ich speichern und vor allem laden:

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:
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;
Im ReadComponent wird aber gleich ins SetLeftPx gesprungen, was ich auch nachvollziehen kann:

Delphi-Quellcode:
procedure TBaseFormElementManager.SetLeftPx(Value: Integer);
begin
  if Assigned(FControl) then
    FControl.Left := Value
  else
    raise EElementNotCreated.Create('No Element Created yet.');
end;
Wo dann FControl auf nil ausgewertet wird und die Exception kommt.

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:

DGL-luke 1. Sep 2006 13:14

Re: Sub-Komponenten serialisieren
 
Niemand einen Tipp für mich?

Khabarakh 1. Sep 2006 13:25

Re: Sub-Komponenten serialisieren
 
Zitat:

Zitat von DGL-luke
Im ReadComponent wird aber gleich ins SetLeftPx gesprungen, was ich auch nachvollziehen kann:

Hm, ich leider nicht ;) . Im von dir geposteten Code deutet aber auch nichts darauf hin, also liegts (hoffentlich) nicht an mir :zwinker: . Wenn dahinter eine published Property steckt, wäre die nächste Frage, warum sie published ist. Denn Left wird ja schon in FControl serialisiert, einmal reicht.

DGL-luke 1. Sep 2006 13:33

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...

Khabarakh 1. Sep 2006 15:20

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.

r2c2 1. Sep 2006 15:25

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

Khabarakh 1. Sep 2006 15:28

Re: Sub-Komponenten serialisieren
 
Zitat:

Zitat von r2c2
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.

Genau diesen Fall fängt er doch im Setter schon längst ab :gruebel: .

Zitat:

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...
Wozu sollte man ein leeres Control erstellen, wenn es eine Zehntelsekunde danach vom Deserialisierer überschrieben wird?

r2c2 1. Sep 2006 15:51

Re: Sub-Komponenten serialisieren
 
Zitat:

Zitat von Khabarakh
Zitat:

Zitat von r2c2
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.

Genau diesen Fall fängt er doch im Setter schon längst ab :gruebel: .

Indem er eine weitere Exception auslöst... jo...

Zitat:

Zitat:

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...
Wozu sollte man ein leeres Control erstellen, wenn es eine Zehntelsekunde danach vom Deserialisierer überschrieben wird?
Ähm... zu viel .NET gemacht? Da wird man verwöhnt, nicht? Is jetzt nur geraten. Ich könnt mir aber vorstellen, dass das in .NET geht(Hab in .NET bisher noch nicht viel gemacht. Serialisierung steht noch auf der Liste...). In Delphi muss man sich aber um so manches noch selber kümmern...

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

DGL-luke 2. Sep 2006 11:35

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.

r2c2 2. Sep 2006 12:52

Re: Sub-Komponenten serialisieren
 
Zitat:

Zitat von DGL-luke
SetSubComponent sollte doch eigentlich genau das machen...

Dann hast du entweder ne andere Hilfe, als ich oder sie nicht richtig gelesen. SetSubComponent regelt ob eine Komponente serialisiert wird. Mit dem Deserialisieren hat das nix zu tun. Dass es damit auch nicht klappt is also kein Wunder...

Zitat:

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.
Probiers aus. Ich vermute, dass das auch nix hilft, da das Control immer noch nicht existiert. Außer du Createst aufgrund des Flags das Control bzw. setzt den Pointer entsprechend. Alleine das raisen deiner Exception zu verhindern wird IMHO nicht funktionieren. Kann mich aber auch irren...

mfg

Christian


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:22 Uhr.
Seite 1 von 3  1 23      

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