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

Вниз

Сохранение свойств компонента в файл   Найти похожие ветки 

 
Vitalik   (2004-07-02 10:58) [0]

Привет! Я тут бьюсь над одной задачкой. У меня есть компонент TChart на котором отображаются графики. Для TChart будут предусмотрены настройки - при помощи TChartEditor или TTeeCommander. Настройки нужно сохранять в поток. То есть пользователь сможет сам устанавливать настройки и сохранять их в файл. Вот в этом проблема - настроек у TChart великое множество. И я отказался от того, чтобы вручную каждую опцию записывать в файл, а потом считывать.

Решил я как-то автоматизировть процесс сохранения настроек. Хотя бы и не всех - это как получится.

Для этого я сначала попробовал всякие TWriter и TReader но мне показалось (долго не углублялся) что они, мягко говоря не работают. Не знаю, может я что-то не то делаю, в общем я пошёл другим путём. Для начала я попытался в дереве отобразить все

параметры компонента и написал такую процедуру:

procedure TForm1.FillProps(ANode: TtreeNode; AObject: TObject);
var
ATypeInfo: PTypeInfo;
ATypeData: PTypeData;
i, n, l: integer;
List: PPropList;
NNode: TTreeNode;
s: string;
ObjProp: TObject;

IntVal: integer;
begin
 ATypeData := GetTypeData(AObject.ClassInfo);
 n := ATypeData.PropCount;

 if N <= 0 then
   Exit;

 GetMem(List, SizeOf(PPropInfo)*N);
 try
   GetPropInfos(AObject.ClassInfo,List);
   for I:= 0 to N - 1 do
     begin
       if AObject.FieldAddress(List[I]^.name) <> nil then showmessage(List[I]^.name);

       case List[I].PropType^.Kind of

         tkEnumeration:
           begin
             ATypeInfo := List[I].PropType^;

             IntVal := GetEnumValue(ATypeInfo,List[i]^.name);
             NNode := tv.Items.AddChild(ANode, List[I]^.name + ": "+ List[I]^.PropType^.Name +" = " + IntToStr(intVal));
           end;
         tkInteger:
           begin
             IntVal := Integer(GetPropValue(AObject, List[i]^.name));
             NNode := tv.Items.AddChild(ANode, List[I]^.name + ": Integer = " + IntToStr(IntVal) );
           end;

         tkFloat:
           begin
             NNode := tv.Items.AddChild(ANode, List[I]^.name + ": " + List[I]^.PropType^.Name + " = " +

FloatToStr(GetFloatProp(AObject, List[i]^.Name)) );
           end;
         tkString, tkLString, tkWString:
           begin
             NNode := tv.Items.AddChild(ANode, List[I]^.name + ": String = " + GetStrProp(AObject, List[i]^.name));

           end;
         tkSet:
           begin

             s := GetSetProp(AObject, List[i]^.name, false);
             Intval := GetOrdProp(AObject, List[i]^.name);
             NNode := tv.Items.AddChild(ANode, List[I]^.name + ": Set of" + List[i]^.PropType^.name +" = " + s + " (" +

IntToStr(IntVal) + ")");

           end;
         tkClass:
           begin
             NNode := tv.Items.AddChild(ANode, List[I]^.name + ": " + List[I]^.PropType^.Name);
             try
               ObjProp := nil;
               ObjProp := GetObjectProp(AObject, List[I]^.name);
               if ( ObjProp <> nil) then
                 FillProps(
                           NNode,
                           ObjProp
                           );
             except

             end;
           end;
       end;

     end;
 finally
   FreeMem(List,SizeOf(PPropInfo)*N);
 end;
end;

Она хоть и выводит ошибку при входе в один из классов, но в целом работает. Кстати, с Enumeration и Set у меня есть отдельные вопросы, но сейчас не об этом.

Потом, немного преобразовав эту процедуру я получил две другие - для чтения и записи настроек в поток/из потока:

procedure TForm1.SaveObjectToStream(AStream: TStream; AObject: TObject);
var
ATypeInfo: PTypeInfo;
ATypeData: PTypeData;
i, n, l: integer;
List: PPropList;

s: string;
StrLen: String;
ObjProp: TObject;

IntVal: integer;
FloatVal: real;
begin
 ATypeData := GetTypeData(AObject.ClassInfo);
 n := ATypeData.PropCount;

 if N <= 0 then
   Exit;

 GetMem(List, SizeOf(PPropInfo)*N);
 try
   GetPropInfos(AObject.ClassInfo,List);
   for I:= 0 to N - 1 do
     begin
       case List[I].PropType^.Kind of

         tkEnumeration:
           begin
             ATypeInfo := List[I].PropType^;

             IntVal := GetEnumValue(ATypeInfo,List[i]^.name);
             AStream.Write(IntVal, SizeOF(IntVal) );
           end;
         tkInteger:
           begin
             IntVal := Integer(GetPropValue(AObject, List[i]^.name));
             AStream.Write(IntVal, SizeOF(IntVal) );
           end;

         tkFloat:
           begin
             FloatVal := GetFloatProp(AObject, List[i]^.Name);
             AStream.Write(FloatVal, SizeOF(FloatVal) );
           end;
         tkString, tkLString, tkWString:
           begin
             s := GetStrProp(AObject, List[i]^.name);
             IntVal := Length(S);
             AStream.Write(IntVal, SizeOf(IntVal) );
             AStream.Write(PChar(s)^, IntVal);
           end;
         tkSet:
           begin
             Intval := GetOrdProp(AObject, List[i]^.name);
             AStream.Write(IntVal, SizeOf(IntVal) );
           end;
         tkClass:
           begin
             try
               ObjProp := nil;
               ObjProp := GetObjectProp(AObject, List[I]^.name);
               if ( ObjProp <> nil) then
                 SaveObjectToStream(AStream, ObjProp);
             except

             end;
           end;
       end;

     end;
 finally
   FreeMem(List,SizeOf(PPropInfo)*N);
 end;
end;

Продолжение - в следующем сообщении, потому что в одно всё не помещается :)



 
Vitalik   (2004-07-02 10:58) [1]

Продолжение.

procedure TForm1.LoadObjectFromStream(AStream: TStream; AObject: TObject);
var
ATypeInfo: PTypeInfo;
ATypeData: PTypeData;
i, n, l: integer;
List: PPropList;

s: string;
StrLen: String;
ObjProp: TObject;

IntVal: integer;
FloatVal: real;
begin
 ATypeData := GetTypeData(AObject.ClassInfo);
 n := ATypeData.PropCount;

 if N <= 0 then
   Exit;

 GetMem(List, SizeOf(PPropInfo)*N);
 try
   GetPropInfos(AObject.ClassInfo,List);
   for I:= 0 to N - 1 do
     begin
       if AObject.FieldAddress(List[I]^.name) <> nil then showmessage(List[I]^.name);

       case List[I].PropType^.Kind of

         tkEnumeration:
           begin
{              AStream.Read(IntVal, SizeOf(IntVal) );
             SetEnumProp(AObject, List[i]^.Name, IntVal);}
           end;
         tkInteger:
           begin
             AStream.Read(IntVal, SizeOf(IntVal) );
             SetInt64Prop(AObject, List[i]^.Name, IntVal);

           end;

         tkFloat:
           begin
             AStream.Read(FloatVal, SizeOf(FloatVal) );
             SetFloatProp(AObject, List[i]^.Name, FloatVal);
           end;
         tkString, tkLString, tkWString:
           begin
             AStream.Read(IntVal, SizeOf(IntVal) );
             SetLength(s, IntVal);
             AStream.Read(PChar(s)^, IntVal);
             SetStrProp(AObject, List[I]^.name, s);
           end;
         tkSet:
           begin
{              AStream.Read(IntVal, SizeOf(IntVal) );
             SetSetProp(AObject, List[I]^.name, );}
           end;
         tkClass:
           begin
             try
               ObjProp := nil;
               ObjProp := GetObjectProp(AObject, List[I]^.name);
               if ( ObjProp <> nil) then
                 LoadObjectFromStream(AStream, ObjProp);
             except

             end;
           end;
       end;

     end;
 finally
   FreeMem(List,SizeOf(PPropInfo)*N);
 end;
end;

Сохраняется в общем-то без проблем (хотя выдаёт ошибку при заходе в тот же класс). При загрузке происходит такая последовательность:
1. Загружается свойство Tag и нормально устанавливается.
2. Загружается свойство name - тоже всё нормально.
3. Загружается свойство Left а вот при установке свойства происходит ошибка. И проблема не в считывании данных из потока, а именно при установке занчения, т.е. в SetInt64Prop(AObject, List[i]^.Name, IntVal);

Так вот что у меня не правильно?

И вообще, что вы думаете о моём огороде? :)
Может действительно можно чем-то стандартным обойтись? Или мой подправить? Лучше - править мой, так пользы больше :)

Спасибо!


 
Анонимщик ©   (2004-07-02 11:37) [2]

Кажется, лучше стандартным все же. Есть, например, ExtLib


 
Vitalik   (2004-07-02 12:08) [3]

Ну вообще-то мне нужно именно сохранять в файл, а не отображать свойства на экране. Но я попробую разобраться в коде ExtLib Где-то там наверняка должен же быть поиск свойств!


 
NeyroSpace ©   (2004-07-02 12:37) [4]

unit Unit1;

interface

uses
 Windows, Messages, Classes, Forms;

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

var
 Form1: TForm1;
 Form2: TForm;
 srtlist: TStringList;

implementation
{$R *.DFM}

function ComponentToString(Component: TComponent): string;
var
 ms: TMemoryStream;
 ss: TStringStream;
begin
 ss := TStringStream.Create(" ");
 ms := TMemoryStream.Create;
 try
   ms.WriteComponent(Component);
   ms.position := 0;
   ObjectBinaryToText(ms, ss);
   ss.position := 0;
   Result := ss.DataString;
 finally
   ms.Free;
   ss.free;
 end;
end;

procedure StringToComponent(Component: TComponent; Value: string);
var
 StrStream:TStringStream;
 ms: TMemoryStream;
begin
 StrStream := TStringStream.Create(Value);
 try
   ms := TMemoryStream.Create;
   try
     ObjectTextToBinary(StrStream, ms);
     ms.position := 0;
     ms.ReadComponent(Component);
   finally
     ms.Free;
   end;
 finally
   StrStream.Free;
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Form2 := TForm.Create(nil);
 srtlist := TStringList.Create;
 srtlist.LoadFromFile("Form2.txt");

 StringToComponent(Form2, srtlist.Text);

 Form2.parent := nil;
 Form2.Visible := true;
 Form2.Caption := "Создана из Form2.DFM";

 srtlist.Free;
end;

end.

==============
файл:
object Form2: TForm
 Left = 195
 Top = 107
 Width = 443
 Height = 218
 Caption = "Form1"
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = "MS Sans Serif"
 Font.Style = []
 OldCreateOrder = False
 PixelsPerInch = 96
 TextHeight = 13
end
==============

Также можно и сохранить


 
TUser ©   (2004-07-02 12:45) [5]

Можно еще использовать TJvFormStorage.


 
Семен Сорокин ©   (2004-07-02 12:49) [6]

и в RX тоже есть


 
Romkin ©   (2004-07-02 12:49) [7]

А нельзя просто использовать TStream.WriteComponent? все published запишется (только не забыть для чтения вернуть позицию в начало ;) )
Есть еще TWriter, TReader, TFiler - они с dfm работают.


 
Анонимщик ©   (2004-07-02 12:53) [8]

Да еще есть и TParser в Classes.pas, с dfm-ами этими поможет работать. А список свойств вытаскивается с помощью функций types.pas. Но со всем вышесказанным его можно и не использовать.


 
Vitalik   (2004-07-02 13:37) [9]

4, 7 приводит примерно к следующему результату:

object Chart1: TChart
 Left = 528
 Top = 96
 Width = 136
 Height = 250
 Title.Text.Strings = (
   "TChart")
 TabOrder = 1
end

2NeyroSpace
Ну вот видите, только эти свойства. А ведь на форме наверняка были и кнопки! Где кнопки-то в полученном файле?

Я не проверял, но думаю, что если добавить в мои процедуры обработку также и массивов tkArray - то тогда будет в дереве отображаться и свойства Controls и Components.

Так что это как бы не то, что мне нужно... Попробуйте запустить процедуру FillProps и станет ясно, что мне нужно пробегаться по большему количеству свойств!

2TUser
TJvFormStorage - а что это и где можно взять?


 
Vitalik   (2004-07-02 15:02) [10]

А кто-нибудь значет, почему вообще не работает

 SetInt64Prop(button1, "left", 100);

?

И как сделать чтоб работало?


 
Amoeba ©   (2004-07-02 18:39) [11]


> TJvFormStorage

В FreeWare библиотеке JVCL http://jvcl.sourceforge.net/



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

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

Наверх





Память: 0.51 MB
Время: 0.03 c
3-1087798199
Леван
2004-06-21 10:09
2004.07.18
Курсоры MS SQL и Delphi


1-1088681196
Aleksandr.
2004-07-01 15:26
2004.07.18
Не могу сделать форму как шаблон


1-1089195017
GreySerg
2004-07-07 14:10
2004.07.18
Почему после отключения debug info exeшник не уменьшается ?


6-1084859339
Сергей12
2004-05-18 09:48
2004.07.18
Соединение Client Server


14-1088522467
pasha_golub
2004-06-29 19:21
2004.07.18
Всем смотреть, это просто шедевр!!!





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский