issamdnn
23-02-2010, 01:19 PM
تخزين وتحميل الخصائص Storing and loading properties:
تقوم دلفي بتخزين النماذج (forms) وعناصرها ضمن ملفات نماذج (ذات اللاحقة .dfm في VCL و اللاحقة .xfm في CLX) , ملف النموذج عملياً يخزن كافة خصائص النموذج وعناصره . عندما يقوم مطورو دلفي بإضافة العناصر التي قمت بكتابتها إلى نماذجهم , فيتوجب على عناصرك أن تمتلك إمكانية تخزين خصائصها إلى ملف النموذج عند الحفظ,, بشكل مشابه وعند التحميل إلى دلفي أو التنفيذ كجزء من التطبيق, يتوجب على العناصر إعادة تخزين نفسها مجدداً من ملف النموذج.
في معظم الأحيان لا داعي للقلق حول هذه القضية فهي تعتبر جزء من السلوك الموروث للعناصر , ولكن أحياناً قد تحتاج إلى تغيير الطريقة التي تقوم بها العناصر بتخزين أو تحميل أنفسها أو طريقة التهيئة عند التحميل وبالتالي ينبغي عليك فهم الآليات والتقنيات التالية :
استخدام تقنيات التخزين والتحميل Using the store-and-load mechanism :
وصف النموذج (form) يتضمن قائمة خصائص النموذج جنباً إلى جنب مع أوصاف مماثلة من كل مكون موجود على النموذج . بما فيها النموذج نفسه وبالتالي فكل نموذج وكل عنصر هو مسؤول عن تخزين و تحميل وصفه الخاص به .
بشكل افتراضي وعندما يقوم العنصر بتخزين نفسه فأنه يقوم بكتابة كافة قيم خصائصه الموجودة في القسم العام (public) وكذلك قيم الخصائص الموجودة في القسم المنشور(published) والتي تختلف عن القيم الافتراضية لهذه الخصائص ويتم ذلك بنفس ترتيب هذه الخصائص في التصريح , فعندما يقوم العنصر بتحميل نفسه فأنه في البداية يقوم بعملية البناء وذلك بوضع كافة قيم الخصائص على قيمها الافتراضية ومن ثم يقوم بقراءة القيم المخزنة و غير الافتراضية منها(non-default).
هذه التقنية الافتراضية تخدم حاجة كافة العناصر ولا تتطلب أي جهد من مبرمج العناصر.وهنالك عدة طرق يستطيع فيها المبرمج القيام بتخصيص عملية التخزين والتحميل لكي تناسب العناصر التي يقوم باشتقاقها (الخاصة به).
تحديد القيم الافتراضية Specifying default values:
تقوم عناصر دلفي بحفظ قيم خصائصها فقط عندما تختلف هذه القيم عن القيم الافتراضية لهذه الخصائص. فإذا لم تقم بتعيين قيم لهذه الخصائص فأن دلفي تفترض بأن الخاصية لا تملك قيمة افتراضية فيما يعني بأن العنصر يقوم دوماً بتخزين الخاصية مهما كانت قيمتها.
لتعيين قيمة افتراضية للخاصية يتم إضافة الموجه default وبعده القيمة الجديدة الإفتارضية في نهاية التصريح عن الخاصية . كما يمكن أيضاً تعيين قيمة افتراضية عند إعادة التصريح عن الخاصية
ملاحظة: تعيين قيمة افتراضية لا يقوم بإسناد هذه القيمة للخاصية بشكل أوتوماتيكي عند إنشاء الكائن(العنصر) , و بالتالي يجب عليك أن تتأكد من أن باني العناصر(constructor) يقوم بإسناد القيم الضرورية لخصائص العناصر الخاصة بك لأن الباني القيمة (0) للخصائص الرقمية (numeric) والقيمة False للمنطقية منها وكذلك القيمة nil للمؤشرات .... إلخ. وإذا كان هنالك مجرد شك حول ذلك قم بإسناد القيمة ضمن منهج الباني كما يوضح ذلك المثال التالي :
type
TStatusBar = class(TPanel(
public
constructor Create(AOwner: TComponent); override;// عملية التجاوز لتعيين قيمة جديدة
published
property Align default alBottom; // إعادة تصريح مع قيمة جديدة
end;
...
constructor TStatusBar.Create(AOwner: TComponent(
begin
inherited Create(AOwner); // إنجاز التهيئة الموروثة
Align := alBottom; // إسناد قيمة جديدة للخاصية
end;
تحديد ما الذي يجب تخزينه Determining what to store:
يمكن للمبرمج التحكم بتخزين خصائص العنصر .وبشكل افتراضي فإن كافة الخصائص المنشورة والمصرح عنها في القسم (published) يتم تخزينها . و يمكنك بالتالي أن تختار عدم تخزين قيمة الخاصية على الإطلاق أو يمكنك تصميم تابع (function) يقوم بالتحديد ديناميكياً فيما إذا يتوجب تخزين الخاصية , وللتحكم بعملية تخزين الخاصية نقوم بإضافة الموجه إلى تصريح الخاصية متبوعاً بالقيمة True, أو False أو باسم التابع المنطقي(نتيجة التابع قيمة منطقية). والمثال التالي يوضح ما تم ذكره :
type
TSampleComponent = class(TComponent)
protected
function StoreIt: Boolean;// تابع من أجل الخاصية الثالثة في القسم المنشور
public
...
published
property Important: Integer stored True; // دوماً يقوم بتخزين قيمة الخاصية
property Unimportant: Integer stored False; // لا يقوم بتخزين قيمة الخاصية على الإطلاق
property Sometimes: Integer stored StoreIt; // التخزين يعتمد على قيمة التابع
end;
التهيئة بعد عملية التحميل Initializing after loading:بعد أن يقوم العنصر بقراءة كافة قيم خصائصه من الوصف المخزن له يقوم باستدعاء منهج وهمي اسمه Loaded والذي يقوم بدوره بتحقيق أو إنجاز التهيئات الضرورية ويتم استدعاء هذا المنهج قبل ظهور النموذج وعناصر التحكم الموجودة فيه . لذلك لا داعي للقلق عندما تومض الشاشة عند التهيئة .
ملاحظة: أول شيء عليك القيام به عند استدعاء لأي منهج Loaded هو استدعاء المنهج الموروث Loaded , هذا يسمح بالتأكد من أن أي خصائص موروثة تتم تهيئتها بشكل صحيح قبل أن تقوم بتهيئة المكونات الخاصة بك .
الكود التالي والذي تم إحضاره من العنصر TDatabase , فبعد التحميل فإن قاعدة البيانات تحاول إعادة تأسيس أية اتصالات كانت مفتوحة أثناء زمن التخزين و تقوم بتحديد كيفية معالجة أي استثناء يحصل أثناء عملية الاتصال:
procedure TDatabase.Loaded;
begin
inherited Loaded; // في البداية قم باستدعاء المنهج الموروث
try
if FStreamedConnected then Open // أعد تأسيس الاتصالات
else CheckSessionName(False);
except
if csDesigning in ComponentState then // في زمن التصميم
Application.HandleException(Self) // دع دلفي تعالج الاستثناء فيما عدا ذلك أعد إطلاق الاستثناء
else raise;
end;
end;
تخزين و تحميل الخصائص غير المنشورة Storing and loading unpublished properties:بشكل افتراضي فأن الخصائص المنشورة (المصرح عنها ضمن القسم published ) هي التي يتم تخزينها وإعادة تحميلها مع المكون, ولكن من الممكن أيضاً تخزين وتحميل الخصائص غير المنشورة , هذا يسمح لمبرمج المكونات بأن يكون لديه خصائص دائمة لا تظهر في مفتش الكائنات(Object Inspector) الخاص بدلفي. وهذا يسمح للعناصر بأن تخزن وتحمل قيم الخاصية التي لا يعرف دلفي كيفية القراءة منها أو الكتابة إليها بسبب كون هذه القيمة معقدة جداً . فعلى سبيل المثال : لا يمكن للكائن TStrings أن يعتمد على السلوك التلقائي لدلفي بعلمية تخزين وتحميل السلاسل (strings) التي يمثلها.وللقيام بذلك يجب أن يستخدم التقنيات التالية :
يمكن حفظ الخصائص غير المنشورة بإضافة كود يخبر دلفي كيف تحمل وتخزن قيم خصائصك غير المنشورة , و لكتابة هذا الكود يجب إتباع الخطوات التالية :
1-إنشاء مناهج لتحميل وتخزين قيم الخصائصCreating methods to store and load property values:لتخزين و تحميل الخصائص الغير المشورة يجب أولا إنشاء منهج لتخزين قيم الخاصية ومنهج أخر لتحميل قيم الخاصية وبالتالي فالمبرمج يملك خيارين .
•إنشاء منهج من النوع TWriterProc لتخزين قيمة الخاصية ومنهج من النوع TReaderProc لتحميل قيمة الخاصية . هذا النهج يتيح للمبرمج الاستفادة من الإمكانيات المدمجة مع دلفي لتخزين وتحميل الأنواع البسيطة , وبالتالي فإذا كان نوع قيمة الخاصية الخاصة بك أحد الأنواع الموجودة في دلفي والتي يعرف دلفي كيفية حفظها و تحميلها فيمكن استخدام هذا النهج .
•أنشئ منهجين من النوع TStreamProc الأول لتخزين قيمة الخاصية والأخر لتحميلها, النوع TStreamProc يأخذ المجرى (stream) كوسيط, كما يمكنك استخدام مناهج المجاري (stream’s) لقراءة وكتابة قيم خصائصك .
فعلى سبيل المثال أعتبر بأن لدينا خاصية تمثل عنصر يتم إنشاءه أثناء وقت التنفيذ runtime وبأن دلفي تعرف كيف تكتب هذه فيمة هذه الخاصية ولكن دلفي لا تقوم بعمل ذلك تلقائياً وذلك لأن المكون لم يتم إنشاء بمصمم النموذج (form designer). فعلى سبيل المثال يقوم المنهج التالي بتحميل وتخزين المكون المنشأ بشكل ديناميكي والذي يمثل قيمة الخاصية المسماة MyCompProperty :
procedure TSampleComponent.LoadCompProperty(Reader: TReader(;
begin
if Reader.ReadBoolean then
MyCompProperty := Reader.ReadComponent(nil);
End;
procedure TSampleComponent.StoreCompProperty(Writer: TWriter);
begin
Writer.WriteBoolean(MyCompProperty <> nil);
if MyCompProperty <> nil then
Writer.WriteComponent(MyCompProperty);
End;
2-تجاوز مناهج تعريف الخصائص Overriding the DefineProperties method:
حالما تنشئ مناهج لتخزين و تحميل قيم الخاصية فانه يتوجب عليك تجاوز DefineProperties الخاصة بالمكونات(العناصر), يقوم دلفي باستدعاء هذا المنهج عند قيامه بتخزين أو تحميل العناصر, في المنهج DefineProperties يتوجب عليك استدعاء المنهج DefineProperty أو المنهج DefineBinaryProperty لمدون الخاصية الحالي . إذا كان مناهج الحفظ والتحميل الخاصة بك تستخدم النوع TWriterProc و TReaderProc عندها يجب استدعاء منهج المدون (الكاتب) DefineProperty . وفي حال كنت إستخدمت مناهج من النوع TStreamProc فيتوجب عندها استدعاء المنهج DefineBinaryProperty بدلاً من المنهج DefineProperty .
ملاحظة : إذا كانت لقيمة الخاصية قيمة افتراضية أو كانت موروثة فلا حاجة لكتابتها .
فعلى سبيل المثال : إذا كان المنهج التالي والمسمى LoadCompProperty من النوع TReaderProc والمنهج StoreCompProperty من النوع TWriterProc عندها يجب تجاوز المنهج DefineProperties كما يلي:
procedure TSampleComponent.DefineProperties(Filer: TFiler);
functionDoWrite: Boolean;
begin
if Filer.Ancestor <> nil then { check Ancestor for an inherited value }
begin
if TSampleComponent(Filer.Ancestor).MyCompProperty = nil then
Result := MyCompProperty <> nil
else if MyCompProperty = nil or
TSampleComponent(Filer.Ancestor).MyCompProperty.Na me <> MyCompProperty.Name then
Result := True
else Result := False;
end
else { no inherited value -- check for default (nil) value }
Result := MyCompProperty <> nil;
End;
begin
inherited; { allow base classes to define properties }
Filer.DefineProperty('MyCompProperty', LoadCompProperty, StoreCompProperty, DoWrite);
End;
الدرس التالي: http://www.delphi4arab.com/forum/showthread.php?t=2692
تقوم دلفي بتخزين النماذج (forms) وعناصرها ضمن ملفات نماذج (ذات اللاحقة .dfm في VCL و اللاحقة .xfm في CLX) , ملف النموذج عملياً يخزن كافة خصائص النموذج وعناصره . عندما يقوم مطورو دلفي بإضافة العناصر التي قمت بكتابتها إلى نماذجهم , فيتوجب على عناصرك أن تمتلك إمكانية تخزين خصائصها إلى ملف النموذج عند الحفظ,, بشكل مشابه وعند التحميل إلى دلفي أو التنفيذ كجزء من التطبيق, يتوجب على العناصر إعادة تخزين نفسها مجدداً من ملف النموذج.
في معظم الأحيان لا داعي للقلق حول هذه القضية فهي تعتبر جزء من السلوك الموروث للعناصر , ولكن أحياناً قد تحتاج إلى تغيير الطريقة التي تقوم بها العناصر بتخزين أو تحميل أنفسها أو طريقة التهيئة عند التحميل وبالتالي ينبغي عليك فهم الآليات والتقنيات التالية :
استخدام تقنيات التخزين والتحميل Using the store-and-load mechanism :
وصف النموذج (form) يتضمن قائمة خصائص النموذج جنباً إلى جنب مع أوصاف مماثلة من كل مكون موجود على النموذج . بما فيها النموذج نفسه وبالتالي فكل نموذج وكل عنصر هو مسؤول عن تخزين و تحميل وصفه الخاص به .
بشكل افتراضي وعندما يقوم العنصر بتخزين نفسه فأنه يقوم بكتابة كافة قيم خصائصه الموجودة في القسم العام (public) وكذلك قيم الخصائص الموجودة في القسم المنشور(published) والتي تختلف عن القيم الافتراضية لهذه الخصائص ويتم ذلك بنفس ترتيب هذه الخصائص في التصريح , فعندما يقوم العنصر بتحميل نفسه فأنه في البداية يقوم بعملية البناء وذلك بوضع كافة قيم الخصائص على قيمها الافتراضية ومن ثم يقوم بقراءة القيم المخزنة و غير الافتراضية منها(non-default).
هذه التقنية الافتراضية تخدم حاجة كافة العناصر ولا تتطلب أي جهد من مبرمج العناصر.وهنالك عدة طرق يستطيع فيها المبرمج القيام بتخصيص عملية التخزين والتحميل لكي تناسب العناصر التي يقوم باشتقاقها (الخاصة به).
تحديد القيم الافتراضية Specifying default values:
تقوم عناصر دلفي بحفظ قيم خصائصها فقط عندما تختلف هذه القيم عن القيم الافتراضية لهذه الخصائص. فإذا لم تقم بتعيين قيم لهذه الخصائص فأن دلفي تفترض بأن الخاصية لا تملك قيمة افتراضية فيما يعني بأن العنصر يقوم دوماً بتخزين الخاصية مهما كانت قيمتها.
لتعيين قيمة افتراضية للخاصية يتم إضافة الموجه default وبعده القيمة الجديدة الإفتارضية في نهاية التصريح عن الخاصية . كما يمكن أيضاً تعيين قيمة افتراضية عند إعادة التصريح عن الخاصية
ملاحظة: تعيين قيمة افتراضية لا يقوم بإسناد هذه القيمة للخاصية بشكل أوتوماتيكي عند إنشاء الكائن(العنصر) , و بالتالي يجب عليك أن تتأكد من أن باني العناصر(constructor) يقوم بإسناد القيم الضرورية لخصائص العناصر الخاصة بك لأن الباني القيمة (0) للخصائص الرقمية (numeric) والقيمة False للمنطقية منها وكذلك القيمة nil للمؤشرات .... إلخ. وإذا كان هنالك مجرد شك حول ذلك قم بإسناد القيمة ضمن منهج الباني كما يوضح ذلك المثال التالي :
type
TStatusBar = class(TPanel(
public
constructor Create(AOwner: TComponent); override;// عملية التجاوز لتعيين قيمة جديدة
published
property Align default alBottom; // إعادة تصريح مع قيمة جديدة
end;
...
constructor TStatusBar.Create(AOwner: TComponent(
begin
inherited Create(AOwner); // إنجاز التهيئة الموروثة
Align := alBottom; // إسناد قيمة جديدة للخاصية
end;
تحديد ما الذي يجب تخزينه Determining what to store:
يمكن للمبرمج التحكم بتخزين خصائص العنصر .وبشكل افتراضي فإن كافة الخصائص المنشورة والمصرح عنها في القسم (published) يتم تخزينها . و يمكنك بالتالي أن تختار عدم تخزين قيمة الخاصية على الإطلاق أو يمكنك تصميم تابع (function) يقوم بالتحديد ديناميكياً فيما إذا يتوجب تخزين الخاصية , وللتحكم بعملية تخزين الخاصية نقوم بإضافة الموجه إلى تصريح الخاصية متبوعاً بالقيمة True, أو False أو باسم التابع المنطقي(نتيجة التابع قيمة منطقية). والمثال التالي يوضح ما تم ذكره :
type
TSampleComponent = class(TComponent)
protected
function StoreIt: Boolean;// تابع من أجل الخاصية الثالثة في القسم المنشور
public
...
published
property Important: Integer stored True; // دوماً يقوم بتخزين قيمة الخاصية
property Unimportant: Integer stored False; // لا يقوم بتخزين قيمة الخاصية على الإطلاق
property Sometimes: Integer stored StoreIt; // التخزين يعتمد على قيمة التابع
end;
التهيئة بعد عملية التحميل Initializing after loading:بعد أن يقوم العنصر بقراءة كافة قيم خصائصه من الوصف المخزن له يقوم باستدعاء منهج وهمي اسمه Loaded والذي يقوم بدوره بتحقيق أو إنجاز التهيئات الضرورية ويتم استدعاء هذا المنهج قبل ظهور النموذج وعناصر التحكم الموجودة فيه . لذلك لا داعي للقلق عندما تومض الشاشة عند التهيئة .
ملاحظة: أول شيء عليك القيام به عند استدعاء لأي منهج Loaded هو استدعاء المنهج الموروث Loaded , هذا يسمح بالتأكد من أن أي خصائص موروثة تتم تهيئتها بشكل صحيح قبل أن تقوم بتهيئة المكونات الخاصة بك .
الكود التالي والذي تم إحضاره من العنصر TDatabase , فبعد التحميل فإن قاعدة البيانات تحاول إعادة تأسيس أية اتصالات كانت مفتوحة أثناء زمن التخزين و تقوم بتحديد كيفية معالجة أي استثناء يحصل أثناء عملية الاتصال:
procedure TDatabase.Loaded;
begin
inherited Loaded; // في البداية قم باستدعاء المنهج الموروث
try
if FStreamedConnected then Open // أعد تأسيس الاتصالات
else CheckSessionName(False);
except
if csDesigning in ComponentState then // في زمن التصميم
Application.HandleException(Self) // دع دلفي تعالج الاستثناء فيما عدا ذلك أعد إطلاق الاستثناء
else raise;
end;
end;
تخزين و تحميل الخصائص غير المنشورة Storing and loading unpublished properties:بشكل افتراضي فأن الخصائص المنشورة (المصرح عنها ضمن القسم published ) هي التي يتم تخزينها وإعادة تحميلها مع المكون, ولكن من الممكن أيضاً تخزين وتحميل الخصائص غير المنشورة , هذا يسمح لمبرمج المكونات بأن يكون لديه خصائص دائمة لا تظهر في مفتش الكائنات(Object Inspector) الخاص بدلفي. وهذا يسمح للعناصر بأن تخزن وتحمل قيم الخاصية التي لا يعرف دلفي كيفية القراءة منها أو الكتابة إليها بسبب كون هذه القيمة معقدة جداً . فعلى سبيل المثال : لا يمكن للكائن TStrings أن يعتمد على السلوك التلقائي لدلفي بعلمية تخزين وتحميل السلاسل (strings) التي يمثلها.وللقيام بذلك يجب أن يستخدم التقنيات التالية :
يمكن حفظ الخصائص غير المنشورة بإضافة كود يخبر دلفي كيف تحمل وتخزن قيم خصائصك غير المنشورة , و لكتابة هذا الكود يجب إتباع الخطوات التالية :
1-إنشاء مناهج لتحميل وتخزين قيم الخصائصCreating methods to store and load property values:لتخزين و تحميل الخصائص الغير المشورة يجب أولا إنشاء منهج لتخزين قيم الخاصية ومنهج أخر لتحميل قيم الخاصية وبالتالي فالمبرمج يملك خيارين .
•إنشاء منهج من النوع TWriterProc لتخزين قيمة الخاصية ومنهج من النوع TReaderProc لتحميل قيمة الخاصية . هذا النهج يتيح للمبرمج الاستفادة من الإمكانيات المدمجة مع دلفي لتخزين وتحميل الأنواع البسيطة , وبالتالي فإذا كان نوع قيمة الخاصية الخاصة بك أحد الأنواع الموجودة في دلفي والتي يعرف دلفي كيفية حفظها و تحميلها فيمكن استخدام هذا النهج .
•أنشئ منهجين من النوع TStreamProc الأول لتخزين قيمة الخاصية والأخر لتحميلها, النوع TStreamProc يأخذ المجرى (stream) كوسيط, كما يمكنك استخدام مناهج المجاري (stream’s) لقراءة وكتابة قيم خصائصك .
فعلى سبيل المثال أعتبر بأن لدينا خاصية تمثل عنصر يتم إنشاءه أثناء وقت التنفيذ runtime وبأن دلفي تعرف كيف تكتب هذه فيمة هذه الخاصية ولكن دلفي لا تقوم بعمل ذلك تلقائياً وذلك لأن المكون لم يتم إنشاء بمصمم النموذج (form designer). فعلى سبيل المثال يقوم المنهج التالي بتحميل وتخزين المكون المنشأ بشكل ديناميكي والذي يمثل قيمة الخاصية المسماة MyCompProperty :
procedure TSampleComponent.LoadCompProperty(Reader: TReader(;
begin
if Reader.ReadBoolean then
MyCompProperty := Reader.ReadComponent(nil);
End;
procedure TSampleComponent.StoreCompProperty(Writer: TWriter);
begin
Writer.WriteBoolean(MyCompProperty <> nil);
if MyCompProperty <> nil then
Writer.WriteComponent(MyCompProperty);
End;
2-تجاوز مناهج تعريف الخصائص Overriding the DefineProperties method:
حالما تنشئ مناهج لتخزين و تحميل قيم الخاصية فانه يتوجب عليك تجاوز DefineProperties الخاصة بالمكونات(العناصر), يقوم دلفي باستدعاء هذا المنهج عند قيامه بتخزين أو تحميل العناصر, في المنهج DefineProperties يتوجب عليك استدعاء المنهج DefineProperty أو المنهج DefineBinaryProperty لمدون الخاصية الحالي . إذا كان مناهج الحفظ والتحميل الخاصة بك تستخدم النوع TWriterProc و TReaderProc عندها يجب استدعاء منهج المدون (الكاتب) DefineProperty . وفي حال كنت إستخدمت مناهج من النوع TStreamProc فيتوجب عندها استدعاء المنهج DefineBinaryProperty بدلاً من المنهج DefineProperty .
ملاحظة : إذا كانت لقيمة الخاصية قيمة افتراضية أو كانت موروثة فلا حاجة لكتابتها .
فعلى سبيل المثال : إذا كان المنهج التالي والمسمى LoadCompProperty من النوع TReaderProc والمنهج StoreCompProperty من النوع TWriterProc عندها يجب تجاوز المنهج DefineProperties كما يلي:
procedure TSampleComponent.DefineProperties(Filer: TFiler);
functionDoWrite: Boolean;
begin
if Filer.Ancestor <> nil then { check Ancestor for an inherited value }
begin
if TSampleComponent(Filer.Ancestor).MyCompProperty = nil then
Result := MyCompProperty <> nil
else if MyCompProperty = nil or
TSampleComponent(Filer.Ancestor).MyCompProperty.Na me <> MyCompProperty.Name then
Result := True
else Result := False;
end
else { no inherited value -- check for default (nil) value }
Result := MyCompProperty <> nil;
End;
begin
inherited; { allow base classes to define properties }
Filer.DefineProperty('MyCompProperty', LoadCompProperty, StoreCompProperty, DoWrite);
End;
الدرس التالي: http://www.delphi4arab.com/forum/showthread.php?t=2692