PDA

View Full Version : بارگزاری یک کامپوننت از یک Resource Stream



Felony
شنبه 10 مرداد 1388, 22:17 عصر
:لبخندساده:سلام

من به وسیله ی کد زیر مشخصات یک کلید رو به صورت ریسورس تو یه استریم میریزم و تو یه فایل ذخیره میکنم :


var
St:TStream;
begin
St:=TFileStream.Create('C:\Info.txt',FMCreate or FMOpenReadWrite);
St.WriteComponentRes('Btn',Button1);
St.Free;
end;

حالا چه طور میتونم این مشخصات که تو فایل ریختم رو بخونم و با توجه بهشون یه کلید بسازم ، میدونم که با متد ReadComponentRes باید این کار رو بکنم ولی نمیدونم چه طور یه دکمه با این مشخصات بسازم .

یعنی میخوام با این کد مشخصات یه کلید رو ذخیره کنم و بعد با یه برنامه دیگه این مشخصات رو از فایل بخونم و کلید رو بسازم .

:چشمک:ممنون

tdkhakpur
شنبه 10 مرداد 1388, 22:31 عصر
سلام

St.WriteComponentRes('Btn',Button1);
این روشی را که شما باهاش کار میکنید درست نیست به این خاطر که یک کلاس از اشیا دارای متد ها و پراپرتی هایی هست که داخل حافظه برای تنظیمات خودشان فضا رزرو کرده اند و کار شما مثل عکاسی از ظاهر قضیه است و به هنگام بازیابی کارایی ندارد(الابته اگر تغییرات غیر استاندارد یعنی کدنویسی برای این کلاس اعمال شود). ول از لحاظ تنظیمات و نحوه ساختار هیچ تغییری به هنگام بازیابی در کلاس شما رخ نخواهد داد.
این هم نمونه ای کد که مال خود کامپایلره داخل دلفی هم هست .


const AnsiString FileName = "C:\\Test";
TStreamableClass* AClassInstance;
AClassInstance = new TStreamableClass(NULL);
WriteComponentResFile(FileName, AClassInstance);
delete AClassInstance;
TComponent* temp = ReadComponentResFile(FileName, NULL);
AClassInstance = static_cast<TStreamableClass*>(temp);
delete AClassInstance;

Felony
شنبه 10 مرداد 1388, 23:00 عصر
سلام

این روشی را که شما باهاش کار میکنید درست نیست به این خاطر که یک کلاس از اشیا دارای متد ها و پراپرتی هایی هست که داخل حافظه برای تنظیمات خودشان فضا رزرو کرده اند و کار شما مثل عکاسی از ظاهر قضیه است و به هنگام بازیابی کارایی ندارد(الابته اگر تغییرات غیر استاندارد یعنی کدنویسی برای این کلاس اعمال شود). ول از لحاظ تنظیمات و نحوه ساختار هیچ تغییری به هنگام بازیابی در کلاس شما رخ نخواهد داد.

سلام و با عرض پوزش ، ولی انگار شما عادت دارین قضایایی که بهشون تسلط کافی ندارین رو دور سرتون بپیچونین و یک سری توضیحات اختراع کنید و ...

اگر نمیشه این کار رو کرد پس این 2 متد WriteComponentRes و ReadComponentRes به چه دردی میخورن ؟

tdkhakpur
شنبه 10 مرداد 1388, 23:04 عصر
سلام
یه دور هم شما به تاپیک ارسالی نگاه کنید اگر خوشتان نیامد بروید خودتان وقت خودتان را بپیچانید.

vcldeveloper
شنبه 10 مرداد 1388, 23:19 عصر
این روشی را که شما باهاش کار میکنید درست نیست
اتفاقا روش درستی هست، و کل IDE دلفی از این روش برای Persistent کردن کامپوننت های دلفی استفاده میکنه؛ یعنی کل فایل های DFM مربوط به فرم های شما در یک پروژه با همین روش ذخیره و بازیابی میشند.


یعنی میخوام با این کد مشخصات یه کلید رو ذخیره کنم و بعد با یه برنامه دیگه این مشخصات رو از فایل بخونم و کلید رو بسازم .
تنها کاری که باید انجام بدید این هست که یک متغیر از نوع TButton داشته باشید، و نتیجه حاصل از ReadComponentRes را به آن اختصاص بدید. ReadComponentRes بعد از خواندن ریسورس مورد نظر، با تشخیص نوع کلاس آن، و جستجو برای کلاس مورد نظر در لیست کلاس های رجیستر شده دلفی، یک نمونه شی از آن کلاس می سازد، و مقادیر خوانده شده از ریسورس را به آن اختصاص می دهد، و یک اشاره گر به نمونه شی ساخته شده به شما تحویل می دهد.

tdkhakpur
شنبه 10 مرداد 1388, 23:26 عصر
کل IDE دلفی از این روش برای Persistent کردن کامپوننت های دلفی استفاده میکنه؛ یعنی کل فایل های DFM مربوط به فرم های شما در یک پروژه با همین روش ذخیره و بازیابی میشند.

سلام
درسته من منظور ایشان را برای اشیایی که بصورت runTime تغییراتی درشان اعمال میشود را عرض کردم نه اشیای خام و ایجاد شده توسط فرم. البته تقسیر از ماست که گفته های خودمان را بصورت مقاله ای به صمع و نظر دوستان نمیرسانیم.

Felony
یک شنبه 11 مرداد 1388, 06:09 صبح
تنها کاری که باید انجام بدید این هست که یک متغیر از نوع TButton داشته باشید، و نتیجه حاصل از ReadComponentRes را به آن اختصاص بدید. ReadComponentRes بعد از خواندن ریسورس مورد نظر، با تشخیص نوع کلاس آن، و جستجو برای کلاس مورد نظر در لیست کلاس های رجیستر شده دلفی، یک نمونه شی از آن کلاس می سازد، و مقادیر خوانده شده از ریسورس را به آن اختصاص می دهد، و یک اشاره گر به نمونه شی ساخته شده به شما تحویل می دهد.
اگر امکان داره یه نمونه کد بزارین .

Felony
یک شنبه 11 مرداد 1388, 21:33 عصر
کسی نمونه کدی برای بارگزاری این فایلها نداره ؟

vcldeveloper
یک شنبه 11 مرداد 1388, 21:47 عصر
من منظور ایشان را برای اشیایی که بصورت runTime تغییراتی درشان اعمال میشود
شما اگر در runtime هم تغییری در شی ایی ایجاد کنید، می تونید به همین طریق تغییرات اعمال شده را در یک فایل یا هر جای دیگه ذخیره کنید.

Felony
یک شنبه 11 مرداد 1388, 22:20 عصر
من هرچی جست و جو میکنم نمیتونم نمونه کدی برای بارگزاری از این فایلها پیدا کنم ، کسی نمونه کدی نداره ؟ لینکی ، چیزی ...

tdkhakpur
یک شنبه 11 مرداد 1388, 23:08 عصر
شما اگر در runtime هم تغییری در شی ایی ایجاد کنید، می تونید به همین طریق تغییرات اعمال شده را در یک فایل یا هر جای دیگه ذخیره کنید.
سلام
حتما موقع بازیابی هم مقادیر قبلی باز بدرد هم خواهد خورد؟؟؟؟؟؟

vcldeveloper
دوشنبه 12 مرداد 1388, 01:01 صبح
حتما موقع بازیابی هم مقادیر قبلی باز بدرد هم خواهد خورد؟
البته که بدرد خواهد خورد. کاربر میتونه با یک کامپوننت خاص، مثلا یک کامپوننت رسم نمودار، در نرم افزار کار کنه، پارامترهای مختلف آن را تغییر بده، و برنامه در زمان خروج تمام مشخصات کامپوننت را با استفاده از سیستم Streaming دلفی ذخیره کنه، و در اجرای بعدی برنامه، آن کامپوننت را دقیقا همانطوری که در آخرین اجرا تنظیم شده بود، بازسازی کنه.

tdkhakpur
دوشنبه 12 مرداد 1388, 01:10 صبح
سلام

و در اجرای بعدی برنامه، آن کامپوننت را دقیقا همانطوری که در آخرین اجرا تنظیم شده بود، بازسازی کنه
ولی فکر کنم در اولین فرصت باید ParentHandleرا Update کرد.

vcldeveloper
دوشنبه 12 مرداد 1388, 03:07 صبح
ولی فکر کنم در اولین فرصت باید ParentHandleرا Update کرد.
این کار در زمان اختصاص مقدار به خصوصیت Parent بطور خودکار انجام میشه. نیازی نیست شما کار خاصی درباره آن انجام بدید.

Saeed_m_Farid
دوشنبه 12 مرداد 1388, 11:03 صبح
من هرچی جست و جو میکنم نمیتونم نمونه کدی برای بارگزاری از این فایلها پیدا کنم ، کسی نمونه کدی نداره ؟ لینکی ، چیزی ...
سلام
احتمالاً شما یه مشکلی که داشتین، اینه که تو پارامتر اول WriteComponentRes مقدار Btn دارید میدین که موقع بازخوانی به مشکل میخوره.
من تو کد زیر دو تا Button برای ذخیره/بازیابی res گذاشتم :

procedure TForm1.btnWriteResClick(Sender: TObject);
var
MyButton: TButton;
begin
btnWriteRes.Free; // Replace with new instance ...
MyButton := TButton(ReadComponentResFile('C:\TestButton.res', btnReadRes));
MyButton.Top := MyButton.Top + 50; // To see the position changes
end;

procedure TForm1.btnReadResClick(Sender: TObject);
begin
with TFileStream.Create('C:\TestButton.res',
fmCreate or fmOpenReadWrite) do try
WriteComponentRes('TButton', btnWriteRes);
finally
Free;
end;
end;
فقط مشکلی که داره اینه که هرچی بعنوان پارامتر دوم ReadComponentResFile بدین، محو میشه!!! نمیشه nil هم داد چون انفجار رخ میده، کد زیر هم واسه خود دلفی بود ولی 2 زار نمی ارزه :

unit StrmExmpl;
{$R-,T-,H+,X+}

interface

uses Classes;

type

TContainedClass = class(TPersistent)
private
FSomeData: Integer;

procedure SetSomeData(Value: Integer);

public
constructor Create;

published
property SomeData: Integer read FSomeData write SetSomeData;

end;

TStreamableClass = class(TComponent)
private
FContainedClass: TContainedClass;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;

published
property ContainedClass: TContainedClass read FContainedClass write FContainedClass;

end;

implementation

procedure TContainedClass.SetSomeData(Value: Integer);
begin
{ Place a breakpoint here and notice how the data is streamed back. }
FSomeData := Value;
end;

constructor TContainedClass.Create;
begin
FSomeData := 42;
end;

constructor TStreamableClass.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FContainedClass := TContainedClass.Create;
end;

destructor TStreamableClass.Destroy;
begin
FContainedClass.Free;
end;

initialization
RegisterClasses([TContainedClass, TStreamableClass]);

finalization

end.
و این هم نحوه استفاده که نمی دونم منظورش چی بوده؟

{
The following OnClick event handler should be added to a button on the
application’s main form. It causes the above classes to be streamed out and in.
Note that you must add StrmExmpl to the uses clause of unit1.
}
procedure TForm1.Button1Click(Sender: TObject);
var
AClassInstance: TStreamableClass;
begin
AClassInstance := TStreamableClass.Create(nil);
WriteComponentResFile('C:\Test.str', AClassInstance);
FreeAndNil(AClassInstance);

AClassInstance := ReadComponentResFile('C:\Test.str', nil) as TStreamableClass;
FreeAndNil(AClassInstance);
end;

بنظرم کلاً چند خط کد واسه اتلاف وقت بوده :لبخند: ...

vcldeveloper
دوشنبه 12 مرداد 1388, 12:20 عصر
بنظرم کلاً چند خط کد واسه اتلاف وقت بوده
اتفاقا کد خوبی هست، چگونگی persistent کردن یک کلاس، و چگونگی ذخیره و بارگزاری آن را نمایش میده. کجاش برای شما گنگ بود؟

Saeed_m_Farid
دوشنبه 12 مرداد 1388, 17:33 عصر
اتفاقا کد خوبی هست، چگونگی persistent کردن یک کلاس، و چگونگی ذخیره و بارگزاری آن را نمایش میده. کجاش برای شما گنگ بود؟
اینکه
FSomeData := 42; قرار میده و بعد میگه breakpoint بذار تا ببینی FSomeData حالا چه Value ای داره؟ که چی بشه؟ قرار بوده ReadComponentResFile و WriteComponentRes توضیح داده بشه، نه اینکه یه کلاس رجیستر کنه بعد FContainedClass رو Free کنه و persistent شدن رو توضیح بده و ...


یه بدبختی میخواد ببینه ReadComponentResFile چطوری استفاده میشه؛ باید بیاد نحوه کامپوننت درست کردن رو آموزش ببینه؟! اصلاً این خارجی ها همینطورین : تو Help هاشون 100 خط کد مینویسن، که 2+2 رو یاد بدن! ما (شایدم فقط من!) به این جور آموزش ها عادت نداریم ...



ضمناً، من کد رو تصحیح کردم، مثلاً تو هدر تابع سازنده Create کلمه Override آورده بود! (Can not override static method) و 5-6 تا خطای Syntax ای هم داشت ، مثلاً جلوی همه Public و Private و ... ها ":" گذاشته بود و بعضی موارد دیگه (البته تو Help دلفی 7)؛ این کد اصلی :
The following code defines a component class (TStreamable class) and a persistent class (TContainedClass) that is the type of a property on the component class.When a button is clicked, an instance of the component class is created, saved to a file, deleted, and then loaded from the file.By setting a breakpoint on the property setter of the TContainedClass SomeData property, you can watch how the streaming system sets property values when it reads them from a file.
The following unit defines the classes to stream:

unit StrmExmpl;
{$R-,T-,H+,X+}
interface
uses Classes
type
TContainedClass = class(TPersistent)
private:
FSomeData: Integer;

procedure SetSomeData(Value: Integer);

public:

constructor Create; override;

// Only published properties
// are automatically streamed.
published:

property SomeData: Integer read FSomeData write SetSomeData;

end;
TStreamableClass = class(TComponent)
private:
FContainedClass: TContainedClass;
public:

constructor Create(AOwner: TComponent); override;

destructor Destroy; override;

// Only published properties
// are automatically streamed.
published:

property ContainedClass: TContainedClass read FContainedClass write FContainedClass;

end;

implementation

procedure TContainedClass.SetSomeData(Value: Integer);
begin
{ Place a breakpoint here and notice how the data is streamed back. }
FSomeData := Value;
end;
constructor TContainedClass.Create;
begin
FSomeData := 42;
end;
constructor TStreamableClass.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FContainedClass = TContainedClass.Create;

end;
destructor TStreamableClass.Destroy;
begin
FContainedClass.Free;
end;
initialization
RegisterClasses([TContainedClass, TStreamableClass]);
finalization
end.

The following OnClick event handler should be added to a button on the application’s main form. It causes the above classes to be streamed out and in. Note that you must add StrmExmpl to the uses clause of unit1.

procedure TForm1.Button1Click(Sender: TObject);

var
AClassInstance: TStreamableClass;
begin
AClassInstance := TStreamableClass.Create(nil);
WriteComponentResFile('C:\Test', AClassInstance);
FreeAndNil(AClassInstance);

AClassInstance := ReadComponentResFile('C:\Test', nil) as TStreamableClass;
FreeAndNil(AClassInstance);
end;
یه موضوع دیگه : به نظر شما چرا "هرچی بعنوان پارامتر دوم ReadComponentResFile بدین، محو میشه!!! نمیشه nil هم داد چون انفجار رخ میده" ؟

vcldeveloper
دوشنبه 12 مرداد 1388, 18:31 عصر
بعد میگه breakpoint بذار تا ببینی FSomeData حالا چه Value ای داره؟ که چی بشه؟
بخاطر اینکه در کد WriteComponentRes این متد رو فراخوانی میکنه، و اگر شما اونجا Breakpoint بزارید، و البته use debug DCU را هم فعال کنید، چگونگی کار WriteComponentRes را می بینید.


یه بدبختی میخواد ببینه ReadComponentResFile چطوری استفاده میشه؛ باید بیاد نحوه کامپوننت درست کردن رو آموزش ببینه؟! اصلاً این خارجی ها همینطورین : تو Help هاشون 100 خط کد مینویسن، که 2+2 رو یاد بدن! ما (شایدم فقط من!) به این جور آموزش ها عادت نداریم ...
این آموزش نحوه کامپوننت ساختن نیست، بلکه دو تا کلاس خیلی ساده هستند که در برنامه نویسی شی گرا شما همواره با امثال آنها سر و کار دارید. اگر از یکی از کلاس های شناخته شده دلفی استفاده می کرد، اون وقت اگر شما با آن کلاس آشنا نبودید، فهم مطلب برای شما سخت میشد. خودش یک کلاس ساده با یک خصوصیت ایجاد کرد و کدش هم گذاشت که شما در فهم اون کلاس مشکلی نداشته باشید، و البته بتونید با پیگیری چگونگی خواندن مقدار خصوصیت آن، به چگونگی Streaming در دلفی پی ببرید.


ضمناً، من کد رو تصحیح کردم، مثلاً تو هدر تابع سازنده Create کلمه Override آورده بود! (Can not override static method) و 5-6 تا خطای Syntax ای هم داشت ، مثلاً جلوی همه Public و Private و ... ها ":" گذاشته بود و بعضی موارد دیگه
اینها مشکلاتی هست که گاهی در زمان ایجاد Help ایجاد میشه. نقصی در صورت مسئله ایجاد نمیکنه.

Saeed_m_Farid
سه شنبه 13 مرداد 1388, 11:40 صبح
بخاطر اینکه در کد WriteComponentRes این متد رو فراخوانی میکنه، و اگر شما اونجا Breakpoint بزارید، و البته use debug DCU را هم فعال کنید، چگونگی کار WriteComponentRes را می بینید.

باور کنید منظور کش دادن مطلب رو ندارم، ولی بازم من متوجه نشدم چرا قراره مطلب به این سادگی اینطوری به ما فهمونده بشه؟


ما یه instance از کلاس TStreamableClass -یعنی AClassInstance- رو می فرستیم واسه WriteComponentResFile ولی باید واسه تابع SetSomeData از کلاس TContainedClass یه breakpoint بذاریم که بفهمیم WriteComponentResFile چی کار میکنه! (باور کنید خودم هم به سختی جمله خودم رو میفهمم) ...
میدونم که یه عضو FContainedClass کلاس TContainedClass واسه TStreamableClass تعریف شده و از این طریق با هم ارتباط دارن ولی واقعاً لازمه که واسه درک WriteComponentRes ما یه کلاس TPersistent داشته باشیم که بعنوان property از یه کلاس مشتق شده از TComponent تعریف بشه و متد SetSomeData اون برای فهم مطلب استفاده بشه؟ هرچی فکر میکنم اگه فقط قصد ما توضیح نحوه کار WriteComponentRes باشه، این روش فقط لقمه رو دور سر پیچوندنه ...



این آموزش نحوه کامپوننت ساختن نیست، بلکه دو تا کلاس خیلی ساده هستند که در برنامه نویسی شی گرا شما همواره با امثال آنها سر و کار دارید. اگر از یکی از کلاس های شناخته شده دلفی استفاده می کرد، اون وقت اگر شما با آن کلاس آشنا نبودید، فهم مطلب برای شما سخت میشد. خودش یک کلاس ساده با یک خصوصیت ایجاد کرد و کدش هم گذاشت که شما در فهم اون کلاس مشکلی نداشته باشید، و البته بتونید با پیگیری چگونگی خواندن مقدار خصوصیت آن، به چگونگی Streaming در دلفی پی ببرید.

آخه جناب کشاورز، RegisterClasses تو کلاس ساده چی کار میکنه؟ مطلقاً نمیگم این کد بدرد نخوره ولی تو این زمینه اضافه کاریه و تا اونجاییکه من میدونم این جور کارها زیاد هم "خیلی ساده" نیستن، لازمه واسه درک این خصوصیت (یا مثلاً فهم چگونگی Streaming در دلفی) همچین کارهایی بکنیم؟

ممنون که وقت گذاشتید ...

vcldeveloper
سه شنبه 13 مرداد 1388, 18:30 عصر
آخه جناب کشاورز، RegisterClasses تو کلاس ساده چی کار میکنه؟ مطلقاً نمیگم این کد بدرد نخوره ولی تو این زمینه اضافه کاریه و تا اونجاییکه من میدونم این جور کارها زیاد هم "خیلی ساده" نیستن، لازمه واسه درک این خصوصیت (یا مثلاً فهم چگونگی Streaming در دلفی) همچین کارهایی بکنیم؟
بخاطر اینکه مکانیزم Streaming در دلفی نیاز به Register کردن کلاس داره. اگر فرضا شما TButton را رجیستر نمی کنید، علتش اینه که دلفی این کار را از قبل براتون انجام داده، ولی وقتی خودتون کلاس جدید می نویسید و میخواید از این قابلیت استفاده کنه، باید کلاس Register بشه. اگر این رو نمی نوشت و کد شما کار نمی کرد، اون وقت می گفتید که چرا تذکر نداده که باید کلاس رو رجیستر کرد.


ما یه instance از کلاس TStreamableClass -یعنی AClassInstance- رو می فرستیم واسه WriteComponentResFile ولی باید واسه تابع SetSomeData از کلاس TContainedClass یه breakpoint بذاریم که بفهمیم WriteComponentResFile چی کار میکنه! (باور کنید خودم هم به سختی جمله خودم رو میفهمم) ...
بله، چون اگر شما روی خودِ WriteComponentRes بخواید BreakPoint بزارید، اونقدر این طرف و آن طرف می چرخید و کارهای مختلفی را در کد می بینید که خودتان حوصله تان سر می رود. آخرش هم متوجه نمیشید کدام کار مربوط به Streaming بود، و کدام کار مربوط به موضوعات دیگه، مثل خواندن از Resource و غیره.
با Breakpoint گذاشتن بر روی آن خط از کد، شما موقعی کد را Trace می کنید که مکانیزم Streaming دلفی فعال شده، و قصد داره مقدار خصوصیت مورد نظر را از شی بخوانه، و آن را در Stream ذخیره کنه.