Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2003.11.20;
Скачать: [xml.tar.bz2];

Вниз

Сохранение сложных объектов   Найти похожие ветки 

 
Walrus   (2003-11-07 18:45) [0]

Всем доброго времени суток!
Есть у меня объект класса А, который содержит в себе список( можно коллекцию - не важно ) объектов класса В, а каждый объект класса В содержит список объектов класса С. Ну, разумеется там не по одному списку и есть другие поля - я упрощённо описываю. Так вот надо сохранить объект класса А в файл( БД нельзя использовать ), чтоб при следующем запуске программы система заработала в том состоянии, в котором её работу прервали. Как Вы, наверное, поняли количество элементов ни в одном списке не известно заранее:(


 
me   (2003-11-07 20:09) [1]

удобно писать в XML-файл, в сети масса примеров сериализации дельфовых объектов в XML


 
Игорь Шевченко   (2003-11-07 20:21) [2]

Stream


 
Walrus   (2003-11-07 22:25) [3]

me, спасибо, поищем... будет вообще супер, если кинешь ссылочку.
Игорь Шевченко, спасибо.
Со Stream у меня и возникли проблемы. Класс А было решено унаследовать от TComponent и в нём сделать TCollection объектов класса В, а в классах В TStringList из объектов класса С. Потом запись

var
ms : TMemoryStream;
fs : TFileStream;
a_Obect : A;

.... //тут всё создаётся и инициализируется

ms.WriteComponent( a_object );
ObjectBinaryToText( ms, fs );


В итоге потом из файла удаётся восстановить всё, кроме списка
TStringList. Я его заполняю, сохраняю, а при следующем запуске в нём 0 элементов! В чём тут может быть дело( кроме моей кориворукости :) )?


 
Игорь Шевченко   (2003-11-07 22:41) [4]

А свойство, имеющее тип StringList объявлено, как published ? Наследники TComponent сохраняют/восстанавливают только published свойства, если не объявлен метод DefineProperties. Лучше было, если бы был приведен код с типами объектов.


 
Walrus   (2003-11-07 22:50) [5]

Игорь Шевченко, огромное спасибо! Дело именно в атрибуте доступа.


 
Walrus   (2003-11-07 23:23) [6]

Так, похоже вопросы остались.
Раньше в TStringList сохранялись только строки( просто потому, что пробовали - как это вообще работает ), теперь добавляем объект( ради этого собственно и брали TStringList ) и он не сохраняется в файл. Почему я так думаю: потому что при попытке его загрузить выдаётся исключение. А вот и код. Не хотелось напрягать, ведь читать чужой код это...но иначе никак:( Класс А -TMailer; класс В - TMailClient; для удобства список не прямо коллекцией сделан, а организован как его потомок - TMailList; класс С - TMy_Connection. Код урезан по максимуму от всякой лишней ерунды.

unit Mailer_ProgrC;

interface

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

type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TMy_Connection = class
public //обернуть в свойство
ID : integer;
constructor Create( value : integer );
end;

TMailClient = class( TCollectionItem )
private
FFolders : TStringList;
public
name : string;
constructor Create( Collection : TCollection ); override;
destructor Destroy; override;
published
property Folders : TStringList read FFolders write FFolders;
end;

TMailList = class( TCollection )
public
function GetMailClient( Index : Integer ) : TMailClient;
procedure SetMailClient( Index : Integer; value : TmailClient );
function Add : TmailClient;
property Items[ Index : Integer ] : TMailClient read GetMailClient
write SetMailClient; default;
end;

TMailer = class( Tcomponent )
private
FMailList : TMailList;
public
constructor Create( AOwner : TComponent ); override;
destructor Destroy; override;
published
property MailList : TMailList read FMailList write FMailList;
end;

var
Form1: TForm1;
Mailer : Tmailer;

implementation

{$R *.dfm}

constructor TMy_Connection.Create ( value : integer );
begin
ID := value;
end;

constructor TmailClient.Create( Collection : TCollection );
begin
inherited;
Folders := TStringList.Create;
name := "name1";
end;

destructor TMailClient.Destroy;
begin
Folders.Free;
inherited;
end;

function TmailList.GetMailClient( Index : Integer ) : TMailClient;
begin
Result := TmailClient( inherited Items[ Index ] );
end;

procedure TMailList.SetmailClient( Index : Integer; Value : TmailClient );
begin
Items[ Index ].Assign( Value );
end;

function TMailList.Add : TMailClient;
begin
Result := TMailClient( inherited Add );
end;

constructor TMailer.Create( AOwner : Tcomponent );
begin
inherited Create( AOwner );
MailList := TMailList.Create( TMailClient );
end;

destructor TMailer.Destroy;
begin
MailList.Free;
inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
m : TMailClient;
ms : TMemoryStream;
fs : TFileStream;
count : integer;
con : TMy_Connection;
begin
Mailer := Tmailer.Create( self );
fs := TFileStream.Create( ExtractFilePath( ParamStr( 0 ) ) + "user.dat",
fmOpenread );
ms := TmemoryStream.Create;

try
ObjectTextToBinary( fs, ms );
ms.Position := 0;
ms.ReadComponent( Mailer );
finally
ms.Free;
fs.Free;
end;

count := Mailer.MailList[1].Folders.Count;
label1.Caption := IntToStr(TMy_Connection(Mailer.MailList[1].Folders.Objects[ count - 1 ]).ID);

con := TMy_Connection.Create( 123 );
Mailer.MailList[1].Folders.AddObject( "hhh",con );
end;

procedure TForm1.FormDestroy(Sender: TObject);
var ms : TMemoryStream;
fs : TFileStream;
begin
fs := TFileStream.Create( ExtractFilePath( ParamStr( 0 ) ) + "user.dat",
fmCreate or fmOpenWrite );
ms := TMemoryStream.Create;

try
ms.WriteComponent( Mailer );
ms.position := 0;
ObjectBinaryToText( ms, fs );
finally
ms.Free;
fs.Free;
end;
end;

end.


 
Игорь Шевченко   (2003-11-07 23:58) [7]

Да, TStringList объекты свои не сохраняет (не умеет).
Чтобы научить его, нужно у TMailClient определить процедуру DefineProperties (определена у всех наследников TPersistent), например



type TMailClient = class(...)
.....
private
procedure ReadFolders (Reader : TReader);
procedure WriteFolders (Writer : TWriter);
protected
procedure DefineProperties(Filer : TFiler); override;
....
end;

...

procedure TMailClient.DefineProperties(Filer: TFiler);

function DoWriteFolders : Boolean;
begin
Result := FFolders.Count > 0;
end;

begin
inherited;
Filer.DefineProperty("Folders", ReadFolders, WriteFolders, DoWriteFolders);
end;

....

procedure TMailClient.ReadFolders(Reader: TReader);
var
S : String;
begin
FFolders.Clear();
Reader.ReadListBegin();
while not Reader.EndOfList do begin
S := Reader.ReadString;
FFolders.AddObject(S, Reader.ReadComponent(nil));
//Подразумевается, что в Objects находятся наследники TComponent
Reader.ReadListEnd();
end;
end;

procedure TTransObject.WriteFolders(Writer: TWriter);
var
I : Integer;
begin
Writer.WriteListBegin();
for I:=0 to Pred(FFolders.Count) do begin
Writer.WriteString(FFolders[I]);
//Подразумевается, что в Objects находятся наследники TComponent
Writer.WriteComponent(FFolders.Objects[I]);
end;
Writer.WriteListEnd();
end;



Или, как второй вариант, написать наследника TStringList, коотрый умеет в методах LoadFromStream/SaveToStream сохранять объекты в Objects

С уважением,


 
Walrus   (2003-11-08 20:17) [8]

Игорь Шевченко, да, спасибо. Только не совсем ясно
в методе ReadFolders(...)
FFolders.AddObject(S, Reader.ReadComponent(nil));
Почему NIL? Там на самом деле локальная переменная, которую мне надо объявить?
И возникла проблема с наследованием элементов, которые поселяем в TStringList, от TComponent:они у нас от TCollectionItem, т.е. оказалось проще отказаться от TStringList в пользу TCollection, иначе там что-то надо с интерфейсами делать? Я правильно всё путаю?


 
Игорь Шевченко   (2003-11-08 21:15) [9]

Walrus (08.11.03 20:17)

nil потому что Reader должен создать компонент и прочитать его свойства, а не читать свойства в заранее созданный.

Если от TCollectionItem, тогда TCollection сама умеет вроде сохранять/читать из потока


 
mc_duck   (2003-11-08 21:29) [10]

А с какой целью делается следущее:

ms.WriteComponent( a_object );
ObjectBinaryToText( ms, fs );

Если сразу в файловый поток писать,то что?


 
Walrus   (2003-11-08 21:59) [11]

Игорь Шевченко, да сохраняет, теперь так и работаем. Просто мне настойчиво внушали, будто TStringList меньше места занимает и с ним быстрее. При попытке добиться аргументов такого мнения мне ничего не ответили. Кто-нибудь может прояснить ситуацию?

mc_duck, сейчас проведём эксперимент по записи двоичных данных в текстовый файл. Ждите отчёта. :)


 
Игорь Шевченко   (2003-11-08 22:14) [12]

Walrus (08.11.03 21:59)

Если и меньше, то ненамного, достаточно посмотреть в Classes.pas


 
mc_duck   (2003-11-08 22:15) [13]

У меня в программе есть класс
TConDisTrig = class(TPaintBox)
public
fTimer:TTimer;
...
published
property Timer:TTimer read fTimer write fTimer;
...
end;

Объект TConDisTrig сохраняется,но не сохраняются свойства fTimer.
В чем дело?



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2003.11.20;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.011 c
1-65864
Chlavik
2003-11-07 19:25
2003.11.20
TStatusBar и OwnerDraw какойто страшный глюк :)


4-66149
Wild Sam
2003-09-26 15:29
2003.11.20
как найти handle окна, потерявшего фокус


3-65729
dimablind
2003-10-31 23:31
2003.11.20
dBGrid


1-65977
Eagle Owl
2003-11-10 18:53
2003.11.20
Вывод текста (TGraphicControl)


1-65887
valerchik
2003-11-07 21:00
2003.11.20
работа приложения, даже если оно не активно





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский