Komponenten benutzen - WriteComponent / ReadComponent - Teil2



  • Ich speichere Objekte auf meinem Formular in eine Datei (WriteComponent). Klappt alles wunderbar

    Jetzt versuche ich das gespeicherte Objekt ion meine LEERE Form zu laden.
    und bekomme immer diese Fehlermeldung:
    "Fehler beim Holen der Daten für '%s'" 😡

    Mein code:

    TFileStream *fs = new TFileStream("D:\\temp\\test1.erp", fmOpenRead);
      TReader *rd = new TReader(fs, 1024);
      rd->ReadComponents(Form1, Form1, NULL);
      delete rd;
      delete fs;
    

    [ Dieser Beitrag wurde am 02.07.2003 um 10:24 Uhr von Jansen editiert. ]



  • In der Hilfe steht explizit, dass Anwendungen TReader-Objekte nicht selbst anlegen (sollen).

    Und wenn du mal die FAQ oder Suchfunktion benutzt hättest wärst du bestimmt auch auf dieses Beispiel gestossen. 😉



  • Auf dieses Bsp. bin ich gestossen. Dieses Bsp bezieht sich auf eine bereits auf der Form vorhandene Komp. Meine Form ist aber nach dem Start zuerst ganz LEER, erst später werden einige Objekte geladen.
    Und das Bsp funzt nur, wenn die geladene Objekte keine Childs haben. z.B. TEdit. Wenn ein Panel andere Unterkomponente enthält, wird auch ein Fehler erzeugt.

    den gleichen Fehler bekomme ich auch wenn ich ReadComponent des Stream-Objekts benutze.
    TStringStream *fs = ...
    TComponent * comp = fs->ReadKomponent(NULL);
    ...



  • Original erstellt von Xqgene:
    Dieses Bsp bezieht sich auf eine bereits auf der Form vorhandene Komp.

    Das Beispiel funktioniert mit dynamisch erzeugten Komponenten genauso.

    Und das Bsp funzt nur, wenn die geladene Objekte keine Childs haben.

    Von Subkomponenten war in deiner Frage nicht die Rede. Aber vielleicht kann Andreas selbst ja nochmal was dazu sagen.

    Wenn ein Panel andere Unterkomponente enthält, wird auch ein Fehler erzeugt.

    Hier nicht. Die Subkomponente wird zwar nicht angezeigt (da sie nicht mit abgespeichert wurde), einen Fehler gibt es aber nicht.



  • Aus der BCB ilfe:

    TComponent* __fastcall ReadComponent(TComponent* Instance);

    ...

    Wenn Instance NULL ist, erstellt ReadComponent auf Grundlage der Typinformationen im Stream eine Komponente und gibt die neue Komponente zurück.

    gibt er eben nicht. nur einen Fehler.

    Und in meinem Bsp werden Subkomponente abgespeichert.

    Das Beispiel funktioniert mit dynamisch erzeugten Komponenten genauso
    Natürlich, wenn die Objekte bereits instanziert wurden. Aber bei mir gibt es noch keine Objekte die Form ist LEER, LEER, LEER... habe ich schon 2 mal geschrieben) die Objekte müssen erst aus einer datei geladen und (laut BCB hilfe automatisch) erzeugt werden.



  • Hallo,

    Das steht in der Hilfe aber zu TStream ReadComponent. Die Funktion ReadComponent von TReader ist etwas anderes.

    Ciao



  • Hi,

    das speichern von SubComponeten wird von den Komponetenen automatisch vorgenommen.

    Es muss lediglich die SubComponente als solche deklariert werden.

    Angenommen du hast in einem CustomCOntrol noch ein Edit- Feld Namens "FEdit" drin als SubComponente:

    Im Konstruktor:

    FEdit=new TEdit(this);
    FEdit->Parent=this;
    FEdit->SetBounds(10,10,100,100);
    FEdit->Name="Edit";// muss
    FEdit->SetSubComponent(true);

    alles weitere wie gehabt.

    ein __proerty einführen:

    __property TEdit* Edit={.....};

    usw.

    Original erstellt von Xqgene :

    TFileStream *fs = new TFileStream("D:\\temp\\test1.erp", fmOpenRead);
      TReader *rd = new TReader(fs, 1024);
      rd->ReadComponents(Form1, Form1, NULL);
      delete rd;
      delete fs;
    

    ähm, das hast du falsch verstanden. das geht anders.

    Wenn du manuel etwas in die *.dfm schreiben willst mach sowas:

    1. Überschrieb di Methode DefineProperties und leg zuwei Methoden an, die das lesen und schreiben steuern.

    In der Hilfe gibst dazu ein Beispiel. Wenn du Probleme damit hast, so werde ich dir auch ein Beisiel schreiben.



  • Nachtrag:

    Dieses sind Themen, die ich in der nächsten Zeit im Tutorial anschneiden werde. Ein paar ausführungen zu *.dfm- Datei sowie die Speichervorgänge dort sind bereits angeschnitten. Schaut doch einfach mal rein..



  • Original erstellt von Xqgene:
    die Objekte müssen erst aus einer datei geladen und (laut BCB hilfe automatisch) erzeugt werden.

    Werden sie doch auch. Um beim Beispiel aus der FAQ zu bleiben:
    -Das Programm einmal starten und die ListBox "abspeichern".
    -Dann (wieder in der IDE), die ListBox von der Form löschen und den entsprechenden Code im savrClick löschen bzw. auskommentieren.
    -Jetzt das Programm wieder starten, den load-Button drücken und voila, es erscheint eine ListBox auf der Form.

    Original erstellt von AndreasW:
    Angenommen du hast in einem CustomCOntrol noch ein Edit- Feld Namens "FEdit" drin als SubComponente

    Aber wie soll das bei nicht-CustomControls funktionieren? Wenn ich also zB. ein Standard-Panel auf die Form und ein Standard-Edit auf dieses Panel lege (egal, ob zur Entwurfs- oder zur Laufzeit) und anschliessend mittels der im Beispiel beschriebenen Methode das Panel abspeichere, dann wird das Edit beim Speichern ignoriert und demzufolge beim Laden auch nicht wieder erzeugt. Ich denke, man müsste hier per Controls durch die Komponenten iterieren und jede für sich abspeichern/laden?



  • Hi,

    sorry, ich hab da was in der eile verwechselt. Ich dachte Xqgene bastelt Komponenten. Seht ihr, das hat man davon, wenn man sich den ganzen Tag mit den Scheiß Dingern rumschlagen muss bie sie einem zum Hals raushängen... 🙄

    mein obriger Beitrag bezieht sich also ausschließlich auf Komponetenentwicklung und ist wohl fehl am Platze. Nicht Xqgene hat es falsch verstanden sondern ich hab gepennt. Ich bitte dafür um Nachsicht.... 😮

    Ich werde mir morgen die Sache nohc etwas genauer ansehen, um dir bei der Problemlösung zu helfen. Heute muss ich noch was fertigkriegen.... *stöhn*



  • Also ich habe es.

    wenn man befor das Objekt gelesen werden, die Klasse registriert, dann funzt es einwandfrei:

    TFileStream fs = new TFileStream("C:\\test.dat", ....
    RegisterClasse(__classid(TPanel));
    TComponent
    comp = fs->ReadComponent(NULL);
    delete fs;

    das geht mit standardkompos und mit eigenen. mit allen unterkomponenten.
    da ich weis welche alle Klassen in der Datei vorkommen können, kan ich sie alle vor dem Lesen registrieren.

    beim abspeichern muss man aber aufpassen. wenn ich zur Entwurfzeit auf die Form ein Panel plaziere und in sie ein anderes, dann haben sie als Owner immer Form1. beim abspeichern mit ...->WriteComponent(Panel1); wird nur Panel1 abgespeichert. und nicht Panel2, obwohl Panel2 liegt in Panel1. um das zu umgehen muss man bei Panel2 Owner auf Panel1 "setzen" z.B. zu Laufzeit Panel2 erzeugen

    Panel2 = new TPanel(Panel1);
    Panel2>Parent = Panel1;

    dann wird mit ...->WriteComponent(Panel1); auch Panel2 abgespeichert als Unterkomponente von Panel1;

    [ Dieser Beitrag wurde am 23.05.2003 um 07:54 Uhr von Xqgene editiert. ]



  • Hi,

    kannst du ein ausführbares Beispiel geben oder den obrigen Beitrag editieren ?

    Ich möchte den Beitrag zur FAQ hinzufügen. Dazu muss aber das Beispiel ausführbar sein...

    Danke.



  • Form mit Panel und zwei Buttons

    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
      : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
      TEdit *e = new TEdit(Panel1); // wichtig! Owner
      e->Parent = Panel1;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      // speichern
      TFileStream *fs = new TFileStream("D:\\Temp\\test.dat", fmCreate);
      fs->WriteComponent(Panel1);
      delete fs;
      // Panel entfernen
      delete Panel1;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      //laden
      TFileStream *fs = new TFileStream("D:\\Temp\\test.dat", fmOpenRead);
      RegisterClass(__classid(TPanel)); // wichtig! ohne Fehler
      RegisterClass(__classid(TEdit));  // wichtig! ohne Fehler
      TComponent* comp = fs->ReadComponent(NULL);
      ((TControl*)comp)->Parent = this;
      delete fs;
    }
    //---------------------------------------------------------------------------
    

    [ Dieser Beitrag wurde am 23.05.2003 um 12:10 Uhr von Xqgene editiert. ]


Anmelden zum Antworten