issamdnn
21-02-2010, 12:11 PM
بسم الله الرحمن الرحيم .
وأفضل الصلاة وأتم التسليم على سيد الخلق الرسول الأمين محمد وعلى آله و أصحابه الطاهرين إلى يوم الدين.
أولاً أشكر إدارة المنتدى على تثبيت الدرسين الأول والثاني. و أقدم الشكر إلى كل من ساهم أو يساهم في إتمام هذه الدورة...
أحب أن أضيف فقط بأن القسم العملي قادم إن شاء الله ولكن هنالك العديد من المواضيع النظرية التي يجب شرحها حتى تكون مرجع لنا عند الإنتقال إلى القسم العملي...
ونبدأ بعون الله بالدرس الثالث.
مناهج القراءة للخصائص هي عبارة عن توابع(Functions) لا تأخذ أية وسائط(بارمترات) بإستثناء ما هو مدون في الأسفل . وتعيد هذه التوابع قيمة من نفس نوع الخاصية . وبالعادة يكون اسم التابع مؤلفاً من Get متبوعاً بأسم الخاصية. على سبيل المثال فإن منهج القراءة للخاصية المسماة Count يكون GetCount.
الإستثناء الوحيد لهذه القاعدة () لا تأخذ أية وسائط(بارمترات) يحصل فقط مع الخصائص من النوع المصفوفي (array properties) والتي سيتم شرحها فيما بعد أو من النوع الذي يستخدم المحدد (Index) والذي أعطينا عليه مثال في الدرس الثاني.
وللحصول على معلومات أكثر تفصيلاً حول المحدد index يمكن الإطلاع على Object Pascal Language Guide بما يخص هذا الموضوع.
مناهج الكتابة (The write method):
مناهج الكتابة هي عبارة عن إجرائيات (procedures) تأخذ وسيط وحيد عادة من نفس نوع الخاصية بإستثناء ما هو مدون في الأسفل , و يمكن تمرير هذا المتحول بإحدى الطريقتين بالمرجع أو بالقيمة . ويمكن تسمية هذه المناهج بأي أسم يريده المستخدم . وهي عادة تكون مؤلفة من Set متبوعة بإسم الخاصية . فعلى سبيل المثال الخاصية Count يكون أسم منهج الكتابة فيها SetCount. والقيمة الممررة كوسيط تصبح القيمة الجديدة للخاصية. والإستثناء الوحيد لهذه القاعدة هو الخصائص من النوع المصفوفي (array properties) والتي سيتم شرحها فيما بعد أو من النوع الذي يستخدم المحدد (Index) والذي أعطينا عليه مثال في الدرس الثاني.
مناهج الكتابة وقبل تغيير قيمة الخاصية عادة تقوم بفحص فيما إذا كانت القيمة الجديدة تختلف عن القيمة الحالية. فعلى سبيل المثال منهج الكتابة التالي للخاصية المسماة Count (هذه الخاصية من النوع integer) تخزن القيمة الحالية في الحقل المسمى FCount :
procedure TMyComponent.SetCount(Value: Integer);
begin
if Value <> FCount then
begin
FCount := Value;
Update;
End;
End;
القيم الإفتراضية للخاصية Default property values :عندما تقوم بالتصريح عن خاصية ما فأنه يمكنك تعيين قيمة إفتراضية لها , ويقوم دلفي بإستخدام القيمة الإفتراضية لتخزين الخاصية في ملف النموذج. ولتعيين قيمة إفتراضية للخاصية قم بألحاق الموجه default بالتصريح الخاص بالخاصية والمثال التالي يوضح ما سبق :
property Cool Boolean read GetCool write SetCool default True;
ملاحظة: التصريح عن قيمة إفتراضية للخاصية لا يجعل للخاصية هذه القيمة .وذلك لأن منهج باني العناصر (component’s constructor) ينبغي عليه تهيئة قيم الخاصية عند البناء . فهو على سبيل المثال يقوم بتعيين القيم النصية على القيمة null و القيم الصحيحة على القيمة 0 والقيم المنطقية على القيمة False .
تعيين عدم وجود قيمة إفتراضية Specifying no default value :
عند التصريح عن خاصية ما يمكن تغيين بأن الخاصية لا تمتلك قيمة إفتراضية . حتى ولو كانت الخاصية الموروثة تمتلك قيمة إفتراضية . ولإجراء ما سبق نقوم بإلحاق الموجه nodefault بتصريح الإجرائية . وعلى سبيل المثال :\
property FavoriteFlavor string nodefault;
عندما تقوم بالتصريح لأول مرة عن خاصية فليس هنالك داعي لجعل هذه الخاصية (خاصيتك الأولى) لا تملك قيمة إفتراضية . والمثال التالي يشرح ما سبق بوضوح أكثر:
ففي هذا المثال تصريح عن عنصر يمتلك خاصية منطقية (Boolean) وحيدة مسماة IsTrue وبعد التصريح سوف نجد المنهج الباني للعنصر السابق والذي يقوم بتهيئة الخاصية :
type
TSampleComponent = class(TComponent(
private
FIsTrue: Boolean;
public
constructor Create(AOwner: TComponent); override;
published
property IsTrue: Boolean read FIsTrue write FIsTrue default True;
end;
...
constructor TSampleComponent.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { إستدعاء الباني الإفتراضي}
FIsTrue := True; تعيين القيمة الإفتراضية للخاصية}}
End;
إنشاء خصائص مصفوفية Creating array properties :
بعض الخصائص تصلح ليتم فهرستها كمصفوفات .على سبيل المثال الخاصية Lines للعنصر TMemo هي قائمة مفهرسة من النصوص والتي تقوم بتشكيل النص المكون لل memo . ويمكن للمستخدم معالجتها كمصفوفة سلاسل محرفية (نصوص).
الخصائص المصفوفية يمكن التصريح عنها كباقي الخصائص مع بعض الإستثناءات :
1- التصريح يتضمن واحد أو أكثر من الفهارس(indexes). ويمكن للفهارس أن تكون من أي نوع .
2- القسمين read و write من التصريح ,يجب أن تكون مناهج وليست حقول .
مناهج القراءة والكتابة لأي خاصية مصفوفية ينبغي أن تمتلك وسائط إضافية تستجيب للفهرسة . كما ينبغي أن تكون الوسطاء بنفس الترتيب وبنفس نوع الفهارس المحددة في التصريح .
هنالك بعض الفوارق الهامة بين الخصائص المصفوفية وبين المصفوفات: فهرس الخاصية المصفوفية ليس من الضروري أن يكون من النوع الصححيح(integer) يمكن فهرسة الخاصية بالنوع النصي (string). والمثال التالي يوضح إمكانية التصريح عن خاصية تعيد قيمة نصية بلإستناد إلى فهرسة صحيحة (integer index):
type
TDemoComponent = class(TComponent)
private
function GetNumberName(Index: Integer): string;
public
property NumberName[Index: Integer]: string read GetNumberName;
end;
...
function TDemoComponent.GetNumberName(Index: Integer): string;
begin
Result := 'Unknown';
case Index of
-MaxInt..-1: Result := 'Negative';
0: Result := 'ZerO';
1..100: Result := 'Small';
101:.MaxInt: Result := 'Large';
End;
End;
إنشاء خصائص مكونات فرعية(الخاصية عبارة عن مكون) Creating properties for subcomponents:بشكل إفتراضي . وعندما تكون قيم الخاصية هي عبارة عن عنصر أخر, فإنك تقوم بإسناد القيمة للخاصية بإضافة مثيل للعنصر على شكل بيانات أو وحدات نمطية . ومن ثم إسناد ذلك المثيل كقيمة للخاصية , و مع ذلك فمن الممكن أيضاً للعنصر الخاص بك أن يقوم بإنشاء مثيل للكائن يقوم بتحقيق قيمة الخاصية. هكذا عناصر مخصصة تدعى مكونات أو عناصر فرعية subcomponents.
العناصر الفرعية يمكن أن تكون مكونات ثابتة (أحفاد للصنف TPersistent) ,خلافاً لمكونات منفصلة يحدث أن يمكن إسنادها كقيم للخاصية ,الخصائص المنشورة للمكونات الفرعية يجري حفظها مع العنصر الذي يقوم بإنشاءها . ومن أجل إنجاز ذلك ينبغي تحقيق الشروط التالية:
1- مالك(Owner)العناصر الفرعية يجب أن يكون العنصر الذي ينشأ هذه الخصائص ويستخدمها كقيمة للخاصية المنشورة. من أجل المكونات الفرعية التي ترث من الصنف TComponent يمكن إنجاز ذلك بتعيين خاصية المالك (Owner).يجب تجاوز override المنهج GetOwner للكائن الثابت ليتم إعادة إنشاء العنصر من جديد.
2- المكونات الفرعية هي أحفاد للصنف TComponent وينبغي أن تحدد كونها مكونات فرعية وذلك بإستدعاء المنهج SetSubComponent نموذجياً يجري إستدعاء المنهج السابق سواء عن طريق المالك أو عن طريق باني المكونات الفرعية.
نموذجياً الخصائص التي تكون قيمها مكونات فرعية تكون خصائص قابلة للقراءة فقط read-only . وذلك لأنه وعند السماح بتغيير قيمة الخاصية فان معين الخاصية يقوم بتحرير المكون الفرعي من جديد . والمثال التالي يوضح معين خاصية قيمتها من النوع TTimer:
procedure TDemoComponent.SetTimerProp(Value: TTimer);
begin
if Value <> FTimer then
begin
if Value <> nil then
begin
if (FTimer <> nil) and( FTimer.Owner = self) then
FTimer.Free;
FTimer := Value;
FTimer,FreeNotification(self);
end
else { nil value}
begin
if FTimer.Owner <> self then
{
FTimer := TTimer.Create(self);
FTimer.SetSubComponent(True);
FTimer.FreeNotification(self);
}
End;
End;
End;
لاحظ بأن معين الخاصية في الأعلى يستدعي المنهج FreeNotification للعنصر الذي يتم تعيينه كقيمة للخاصية .هذا الإستدعاء للمنهج السابق يسمح بالتأكد من أن العنصر الذي هو قيمة للخاصية يرسل إعلام قبل تهديمه في الذاكرة , ويقوم بإرسال هذا الإعلام بإستدعاءه للمنهج Notification ويمكن معالجة هذا الإعلام بتجاوز overriding المنهج Notification كما في الشكل التالي:
procedure TDemoComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FTimer) then
FTimer := nil;
End;
الدرس التالي: http://www.delphi4arab.com/forum/showthread.php?t=2621
وأفضل الصلاة وأتم التسليم على سيد الخلق الرسول الأمين محمد وعلى آله و أصحابه الطاهرين إلى يوم الدين.
أولاً أشكر إدارة المنتدى على تثبيت الدرسين الأول والثاني. و أقدم الشكر إلى كل من ساهم أو يساهم في إتمام هذه الدورة...
أحب أن أضيف فقط بأن القسم العملي قادم إن شاء الله ولكن هنالك العديد من المواضيع النظرية التي يجب شرحها حتى تكون مرجع لنا عند الإنتقال إلى القسم العملي...
ونبدأ بعون الله بالدرس الثالث.
مناهج القراءة للخصائص هي عبارة عن توابع(Functions) لا تأخذ أية وسائط(بارمترات) بإستثناء ما هو مدون في الأسفل . وتعيد هذه التوابع قيمة من نفس نوع الخاصية . وبالعادة يكون اسم التابع مؤلفاً من Get متبوعاً بأسم الخاصية. على سبيل المثال فإن منهج القراءة للخاصية المسماة Count يكون GetCount.
الإستثناء الوحيد لهذه القاعدة () لا تأخذ أية وسائط(بارمترات) يحصل فقط مع الخصائص من النوع المصفوفي (array properties) والتي سيتم شرحها فيما بعد أو من النوع الذي يستخدم المحدد (Index) والذي أعطينا عليه مثال في الدرس الثاني.
وللحصول على معلومات أكثر تفصيلاً حول المحدد index يمكن الإطلاع على Object Pascal Language Guide بما يخص هذا الموضوع.
مناهج الكتابة (The write method):
مناهج الكتابة هي عبارة عن إجرائيات (procedures) تأخذ وسيط وحيد عادة من نفس نوع الخاصية بإستثناء ما هو مدون في الأسفل , و يمكن تمرير هذا المتحول بإحدى الطريقتين بالمرجع أو بالقيمة . ويمكن تسمية هذه المناهج بأي أسم يريده المستخدم . وهي عادة تكون مؤلفة من Set متبوعة بإسم الخاصية . فعلى سبيل المثال الخاصية Count يكون أسم منهج الكتابة فيها SetCount. والقيمة الممررة كوسيط تصبح القيمة الجديدة للخاصية. والإستثناء الوحيد لهذه القاعدة هو الخصائص من النوع المصفوفي (array properties) والتي سيتم شرحها فيما بعد أو من النوع الذي يستخدم المحدد (Index) والذي أعطينا عليه مثال في الدرس الثاني.
مناهج الكتابة وقبل تغيير قيمة الخاصية عادة تقوم بفحص فيما إذا كانت القيمة الجديدة تختلف عن القيمة الحالية. فعلى سبيل المثال منهج الكتابة التالي للخاصية المسماة Count (هذه الخاصية من النوع integer) تخزن القيمة الحالية في الحقل المسمى FCount :
procedure TMyComponent.SetCount(Value: Integer);
begin
if Value <> FCount then
begin
FCount := Value;
Update;
End;
End;
القيم الإفتراضية للخاصية Default property values :عندما تقوم بالتصريح عن خاصية ما فأنه يمكنك تعيين قيمة إفتراضية لها , ويقوم دلفي بإستخدام القيمة الإفتراضية لتخزين الخاصية في ملف النموذج. ولتعيين قيمة إفتراضية للخاصية قم بألحاق الموجه default بالتصريح الخاص بالخاصية والمثال التالي يوضح ما سبق :
property Cool Boolean read GetCool write SetCool default True;
ملاحظة: التصريح عن قيمة إفتراضية للخاصية لا يجعل للخاصية هذه القيمة .وذلك لأن منهج باني العناصر (component’s constructor) ينبغي عليه تهيئة قيم الخاصية عند البناء . فهو على سبيل المثال يقوم بتعيين القيم النصية على القيمة null و القيم الصحيحة على القيمة 0 والقيم المنطقية على القيمة False .
تعيين عدم وجود قيمة إفتراضية Specifying no default value :
عند التصريح عن خاصية ما يمكن تغيين بأن الخاصية لا تمتلك قيمة إفتراضية . حتى ولو كانت الخاصية الموروثة تمتلك قيمة إفتراضية . ولإجراء ما سبق نقوم بإلحاق الموجه nodefault بتصريح الإجرائية . وعلى سبيل المثال :\
property FavoriteFlavor string nodefault;
عندما تقوم بالتصريح لأول مرة عن خاصية فليس هنالك داعي لجعل هذه الخاصية (خاصيتك الأولى) لا تملك قيمة إفتراضية . والمثال التالي يشرح ما سبق بوضوح أكثر:
ففي هذا المثال تصريح عن عنصر يمتلك خاصية منطقية (Boolean) وحيدة مسماة IsTrue وبعد التصريح سوف نجد المنهج الباني للعنصر السابق والذي يقوم بتهيئة الخاصية :
type
TSampleComponent = class(TComponent(
private
FIsTrue: Boolean;
public
constructor Create(AOwner: TComponent); override;
published
property IsTrue: Boolean read FIsTrue write FIsTrue default True;
end;
...
constructor TSampleComponent.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { إستدعاء الباني الإفتراضي}
FIsTrue := True; تعيين القيمة الإفتراضية للخاصية}}
End;
إنشاء خصائص مصفوفية Creating array properties :
بعض الخصائص تصلح ليتم فهرستها كمصفوفات .على سبيل المثال الخاصية Lines للعنصر TMemo هي قائمة مفهرسة من النصوص والتي تقوم بتشكيل النص المكون لل memo . ويمكن للمستخدم معالجتها كمصفوفة سلاسل محرفية (نصوص).
الخصائص المصفوفية يمكن التصريح عنها كباقي الخصائص مع بعض الإستثناءات :
1- التصريح يتضمن واحد أو أكثر من الفهارس(indexes). ويمكن للفهارس أن تكون من أي نوع .
2- القسمين read و write من التصريح ,يجب أن تكون مناهج وليست حقول .
مناهج القراءة والكتابة لأي خاصية مصفوفية ينبغي أن تمتلك وسائط إضافية تستجيب للفهرسة . كما ينبغي أن تكون الوسطاء بنفس الترتيب وبنفس نوع الفهارس المحددة في التصريح .
هنالك بعض الفوارق الهامة بين الخصائص المصفوفية وبين المصفوفات: فهرس الخاصية المصفوفية ليس من الضروري أن يكون من النوع الصححيح(integer) يمكن فهرسة الخاصية بالنوع النصي (string). والمثال التالي يوضح إمكانية التصريح عن خاصية تعيد قيمة نصية بلإستناد إلى فهرسة صحيحة (integer index):
type
TDemoComponent = class(TComponent)
private
function GetNumberName(Index: Integer): string;
public
property NumberName[Index: Integer]: string read GetNumberName;
end;
...
function TDemoComponent.GetNumberName(Index: Integer): string;
begin
Result := 'Unknown';
case Index of
-MaxInt..-1: Result := 'Negative';
0: Result := 'ZerO';
1..100: Result := 'Small';
101:.MaxInt: Result := 'Large';
End;
End;
إنشاء خصائص مكونات فرعية(الخاصية عبارة عن مكون) Creating properties for subcomponents:بشكل إفتراضي . وعندما تكون قيم الخاصية هي عبارة عن عنصر أخر, فإنك تقوم بإسناد القيمة للخاصية بإضافة مثيل للعنصر على شكل بيانات أو وحدات نمطية . ومن ثم إسناد ذلك المثيل كقيمة للخاصية , و مع ذلك فمن الممكن أيضاً للعنصر الخاص بك أن يقوم بإنشاء مثيل للكائن يقوم بتحقيق قيمة الخاصية. هكذا عناصر مخصصة تدعى مكونات أو عناصر فرعية subcomponents.
العناصر الفرعية يمكن أن تكون مكونات ثابتة (أحفاد للصنف TPersistent) ,خلافاً لمكونات منفصلة يحدث أن يمكن إسنادها كقيم للخاصية ,الخصائص المنشورة للمكونات الفرعية يجري حفظها مع العنصر الذي يقوم بإنشاءها . ومن أجل إنجاز ذلك ينبغي تحقيق الشروط التالية:
1- مالك(Owner)العناصر الفرعية يجب أن يكون العنصر الذي ينشأ هذه الخصائص ويستخدمها كقيمة للخاصية المنشورة. من أجل المكونات الفرعية التي ترث من الصنف TComponent يمكن إنجاز ذلك بتعيين خاصية المالك (Owner).يجب تجاوز override المنهج GetOwner للكائن الثابت ليتم إعادة إنشاء العنصر من جديد.
2- المكونات الفرعية هي أحفاد للصنف TComponent وينبغي أن تحدد كونها مكونات فرعية وذلك بإستدعاء المنهج SetSubComponent نموذجياً يجري إستدعاء المنهج السابق سواء عن طريق المالك أو عن طريق باني المكونات الفرعية.
نموذجياً الخصائص التي تكون قيمها مكونات فرعية تكون خصائص قابلة للقراءة فقط read-only . وذلك لأنه وعند السماح بتغيير قيمة الخاصية فان معين الخاصية يقوم بتحرير المكون الفرعي من جديد . والمثال التالي يوضح معين خاصية قيمتها من النوع TTimer:
procedure TDemoComponent.SetTimerProp(Value: TTimer);
begin
if Value <> FTimer then
begin
if Value <> nil then
begin
if (FTimer <> nil) and( FTimer.Owner = self) then
FTimer.Free;
FTimer := Value;
FTimer,FreeNotification(self);
end
else { nil value}
begin
if FTimer.Owner <> self then
{
FTimer := TTimer.Create(self);
FTimer.SetSubComponent(True);
FTimer.FreeNotification(self);
}
End;
End;
End;
لاحظ بأن معين الخاصية في الأعلى يستدعي المنهج FreeNotification للعنصر الذي يتم تعيينه كقيمة للخاصية .هذا الإستدعاء للمنهج السابق يسمح بالتأكد من أن العنصر الذي هو قيمة للخاصية يرسل إعلام قبل تهديمه في الذاكرة , ويقوم بإرسال هذا الإعلام بإستدعاءه للمنهج Notification ويمكن معالجة هذا الإعلام بتجاوز overriding المنهج Notification كما في الشكل التالي:
procedure TDemoComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FTimer) then
FTimer := nil;
End;
الدرس التالي: http://www.delphi4arab.com/forum/showthread.php?t=2621