Конференция "Компоненты" » Как сохранить/записать экземпляр класса? [D7, WinXP]
 
  • Святослав (27.10.07 14:30) [0]
    Где ошибка?

    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls;

    type
     TForm1 = class(TForm)
       Button1: TButton;
       Button2: TButton;
       procedure Button1Click(Sender: TObject);
       procedure Button2Click(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

     My=class(TComponent)
     public
       s:string;
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.Button1Click(Sender: TObject);
    var
     f:TFileStream;
     x:My;
    begin
     f:=TFileStream.Create('d:\Test',fmCreate or fmopenwrite);
     x:=My.Create(nil);
     x.s:='Test';
     f.WriteComponent(x);
     f.Free;
     x.Free;
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    var
     f:TFileStream;
     x:My;
    begin
     f:=TFileStream.Create('d:\Test',fmOpenRead);
     x:=f.ReadComponent(nil) as My;
     ShowMessage(x.s);
     f.Free;
     x.Free;
    end;

    begin
     RegisterClass(My);
    end.
  • Джо © (27.10.07 19:44) [1]
    > Где ошибка?

    S должно быть свойством. S должно быть объявлено в секции published. Ну и должно, ес-но, иметь сеттер.
  • Юрий Зотов © (28.10.07 11:29) [2]
    Точнее, не сам сеттер, а атрибут write.
  • Святослав (28.10.07 22:37) [3]
    Спасибо буду пробовать :)
  • Святослав (29.10.07 17:23) [4]

    > S должно быть объявлено в секции published.

    Не подходит, мне надо свойства-массивы сохранять, а их нельзя объявить published :(

    Есть другой способ сохранение экземпляров?
  • Юрий Зотов © (29.10.07 17:28) [5]
    > Святослав   (29.10.07 17:23) [4]

    > а их нельзя объявить published

    Можно, в виде индексированного свойства (cм., например, объявление свойства Items у класса TStrings). Кроме того, с помощью DefineProperties можно сохранять свойства любого типа.
  • Святослав (29.10.07 17:56) [6]

    > Можно, в виде индексированного свойства

    если так:
    published
       property Word[i:integer]:string read GetS Write SetS;
    то выдает - Published property 'Word' cannot be of type ARRAY (E2188)


    > cм., например, объявление свойства Items у класса TStrings

    в Delphi 2006 у класса TStrings нет свойства Items, TList подойдет?
  • Джо © (29.10.07 19:16) [7]
    Оставляя за пределом обсуждений факт целесообразности динамического массива в качестве свойства, а также некоторые нюансы реализации, общая схема может быть такова:

    unit Unit2;

    interface
    uses SysUtils, Classes;

    type
     TWords = array of string;

     TMyStoreClass = class (TComponent)
     private
       FWords: TWords;
       procedure SetWords(const Value: TWords);
       procedure ReadWords (Reader: TReader);
       procedure WriteWords (Writer: TWriter);
     protected
       procedure DefineProperties(Filer: TFiler); override;
     public
       property Words: TWords read FWords write SetWords;
       procedure AddWord (const S: string);
     end;

    implementation

    procedure TMyStoreClass.AddWord(const S: string);
    begin
     SetLength (FWords,Length(FWords)+1);
     FWords[Length(FWords)] := S
    end;

    procedure TMyStoreClass.DefineProperties(Filer: TFiler);
    begin
     inherited;
     Filer.DefineProperty('Words',ReadWords,WriteWords,True);
    end;

    procedure TMyStoreClass.ReadWords(Reader: TReader);
    var
     I,
     WordCount,
     WordLength: Integer;
     S: string;
    begin
     Reader.Read(WordCount,SizeOf(WordCount));
     SetLength (FWords,WordCount);
     for I := 0 to WordCount-1 do
     begin
       Reader.Read(WordLength,SizeOf(WordLength));
       SetLength (S,WordLength);
       Reader.Read(S[1],WordLength);
       FWords[I] := S
     end;
    end;

    procedure TMyStoreClass.SetWords(const Value: TWords);
    begin
     FWords := Value;
    end;

    procedure TMyStoreClass.WriteWords(Writer: TWriter);
    var
     I,
     WordCount,
     WordLength: Integer;
     S: string;
    begin
     WordCount := Length(FWords);
     Writer.Write(WordCount,SizeOf(WordCount));
     for I := 0 to WordCount-1 do
     begin
       S := Words[I];
       WordLength := Length(S);
       Writer.Write(WordLength,SizeOf(WordLength));
       Writer.Write(S[1],WordLength);
     end;
    end;

    end.

  • Джо © (29.10.07 19:17) [8]
    Т.е., это пример использования DefineProperties для сохранения/чтения *любого* свойства, а не панацея для данного случая, конечно.
  • Святослав (29.10.07 20:55) [9]
    проблема: при попытке обращения FWords через Words или AddWord, программа вылетает! Если б это был класс его надо было бы создать, но так как это массив достаточно задать размерность что и происходит в AddWord…
    В чем ошибка?
  • Джо © (29.10.07 21:16) [10]
    Да я просто показал, как работать с DefineProperty, остальное -- довесок, написанный с закрытыми глазами за минуту, на него не нужно обращать внимание. А если начать обращать, то видно что в AddWord содержится ошибка, а именно:
     FWords[Length(FWords)-1] := S


    :)
  • Джо © (29.10.07 21:18) [11]
    Вот, если угодно, код проверки:

    procedure TForm1.Button1Click(Sender: TObject);
    var
     I: Integer;
     Store: TMyStoreClass;
     Fs: TFileStream;
    begin
     Store := TMyStoreClass.Create(nil);
     try
       Store.AddWord('First');
       Store.AddWord('Second');

       Fs := TFileStream.Create('d:\store.dat',fmCreate);
       try
         Fs.WriteComponent(Store);
       finally
         Fs.Free
       end;
     finally
       Store.Free;
     end;

     Store := TMyStoreClass.Create(nil);
     try
       Fs := TFileStream.Create('d:\store.dat',fmOpenRead);
       try
         Fs.ReadComponent(Store);
       finally
         Fs.Free
       end;
       for I := Low(Store.Words) to High(Store.Words) do
       begin
         ShowMessage (Store.Words[I]);
       end;
     finally
       Store.Free;
     end;
    end;

  • Святослав (30.10.07 01:05) [12]
    Действительно ошибка :)
    Если я правильно понял то ReadComponent подставляет сохраненные значения в свойство Words (в обход AddWord) или там другой механизм?
  • Джо © (30.10.07 01:56) [13]
    > [12] Святослав   (30.10.07 01:05)
    > Действительно ошибка :)
    > Если я правильно понял то ReadComponent подставляет сохраненные
    > значения в свойство Words (в обход AddWord) или там другой
    > механизм?

    Там другой механизм. Вся механика — в классах TComponent и TPersistent. Изучайте, там на самом деле много «вкусных» и поучительных вещей. :)
  • Святослав (30.10.07 11:52) [14]
    Огромное всем и Джо отдельное человечиское спасибо :)))
    Заключение:
    Много работать вредно! Я забыл проинициализировать свой объект, поэтому прога вылетала, а из-за усталости немог увидеть :) Если глюк неиспровляеться в течении полу часа лутше лечь поспать и все проидет :)
 
Конференция "Компоненты" » Как сохранить/записать экземпляр класса? [D7, WinXP]
Есть новые Нет новых   [134427   +38][b:0][p:0.002]