الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

لنبدا دورة دلفي

مغلقرائج
بدأه madi في 5 يونيو 2001 · 40 رد · 26,369 مشاهدة · في أرشيف منتدى الدلفي
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

نريد شي دا فائدة للجميع :

لذلك قررت ان ابدا في فكرة جميلة , وهي دورة دلفي يتعاون فيها الجميععععععععع , كل مرة نطرح موضوع و الجميع يضيف على هذا الموضوع ما يفيد من ملاحضات حتى تعم الفائدة

انبدا

برنامج دلفي يتكون من وحدتين رئيسيتين هما

1-program البرنامج الرئيسي

2-unit وحدات اخري

البرنامج في دلفي يتكون من برنامج رئيسي واحد , ومجموعة وحدات اخرى (عددها غير محدد).

1- البرنامج الرئيسي ياخد الهيكلية التالية :

program اسم البرنامج;

uses

جزاء يستخدم عندما نريد استخدام دوال او برامج موجودة في ملف أخر .

begin

اوامر البرنامج الرئيسي

end.

----

2- الوحدات الاخرى

وتاخد الهيكليةالتالية

unit Unit1; { تعريف الوحدة}

interface جزء التعريفات حيت يتم في هذا الجزء تعريف كل المتغيرات الخارجية في هذه الوحدة

uses { جملة استخدام دوال و تجهيزات اضافية}

implementation جزء الذي يكتب فيه اوامر و دوال لغة الدلفي

initialization جزء اعطاء القيم البتدائية للمتغيرات

finalization تنفد عندما ينتهي تنفيد البرنامج الرئيسي , لكي نتمكن من التعامل مع المتغيرات التي قد نكون قد حجزناه في جملة initialization ز

{ }

end.نهاية الوحدة

1
#2

اخي جميل جدا ماتقوم به اكمل الدروس وسوف اضعها باسمك في قسم دروس اخصصه للدلفي والله يكون بالعون وإن شاء الله يتعاون الجميع بالنسبة لي لا افقه شيء بدلفي

جديد مدونتي الشخصية http://www.badwi.com

ادعو لنا بظاهر الغيب

MyBooksExchange.jpg

#3

بسم الله الرحمن الرحيم

اولاً اشكر الأخ مادي على مشاركته الطيبه

وعلى الفكرة ايضاً

ولكن لدي ملاحظه بسيطه وهي انه عندما تشرح شي اضرب عليه مثالاً

لكي تتضح الفكرة اكثر

واكرر شكري لك

وثانياً اشكر الأخ محمد بدوي على جهوده الجباره

وتقبلوا تحياتي اخوكم SUM

#4

عبارة IF,Then,Else:

هذه العبار هي عبارة اشتراطيه

فمثلاً انت تريد انه اذا كان المتغير i يساوي القيمة 5 يتم اغلاق البرنامج

فاليك هذا الكود

var
i:integer;
begin
if i=5 then
close
else
ShowMessage('arabdevelopers');

ففي هذا الكود يقوم البرنامج بفحص I فعندما تكون I=5 يقوم بأغلاق البرنامج

وعبارة else تفيد عدم حدوث الشرط فعندما تكون I لاتساوي 5 فعندها ستظر لك رسالة مكتوب بها (arabdevelopers)

ولكن الكود السابق يطبق لك السطر الأول بعد الشرط فقط فعندما تريد فعل اكثر من امر قم بكتابة Begin بعد الشرط وفي نهاية الأوامر ضع End

كما في هذا المثال:

var
i:integer;
begin
if i=5 then
begin
form1.Hide;
ShowMessage('OK');
end
else
begin
ShowMessage('arabdevelopers');
end;

ارجو ان تكون قداضحت لكم (( وهذه العبارة كثيرة الأستخدام في دلفي ))

لكم كل شكر وتقدير اخوكم SUM

تم تعديل هذه المشاركة بواسطة ORWA في 20 نوفمبر 2004 في 23:49

#5

عبارة case

هذه العبارة مشابهه للعبارة IF,Then ولكنها متطورة بعض الشيء

ففي هذه العبارة تستطيع اشتراط اموامر كثيرة فبدلاً من ان تكتب هذا الكود في عبارة IF,Then:

Var
i:integer;
begin
if i=1 then
ShowMessage('1');
if i=2 then
ShowMessage('2');
if i=3 then
ShowMessage('3');
....

فيمكنك عملها بعبارة case ببضعة اسطر انظر الى المثال التالي:

var
i:integer;
begin
case i of
1: ShowMessage('1');
2: ShowMessage('2');
3: ShowMessage('3');
...

وهاكذا

ارجو ان تكون قد اتضحت لكم

لكم كل شكر وتقدير اخوكم SUM

تم تعديل هذه المشاركة بواسطة ORWA في 20 نوفمبر 2004 في 23:50

#6

سلام

شكرا للخ سم .

وتعقيبا على كلامه .

فان اي جملة اساسية في لغة تستخدم نضام block المقاطع .

وساشرح معني ذلك

متلا جملة if , تستطيع تنفيد مقطع واحد فقط بعدها

والمقطع ينقسم الى جزئين :

1- جملة واحدة

2- مجموعة جمل وفي هذه الحالة نستخدم عبارة begin ,end

متلا

الحالة الاولى

if(x > 5) then
;y=5

الحالة التانية

if(x=5) then
begin
;y=6
;h=2
;end

اي انه اذا احتجنا لتنفيد اكتر من جملة تحت جملة رئيسية فاننا نستخدم begin , end

وشكرا

تم تعديل هذه المشاركة بواسطة ORWA في 20 نوفمبر 2004 في 23:50

#7

برنامج دلفي يتكون من

مشروع project و هو البرنامج الرئيسي

ووحدات اخري unit.

مشروع اارة مكتبة

-------------------------------------------- ......

| | |

الشاشة الرئيسية عرض الكتب شؤو الموظفين .....

نلا حظ ان مشروع ادارة المكتبة يتكون من ملف المشروع نفسه

ومجموعة وحدات اخرى متل الشاشة الرئيسية او عرض الكتب ....

المشروع يتكون من ملف واحد

بينما الوحدات تتكون من

وحدة و شكل unit ,Form

الوحدة هي المكان الذي نكتب فيه خطوات البرمجو

و الشكل هو المكان الذي نقوم بتصميمه و و ضع الاشكال الاخرى عليه (بمعنى انه واجهة التطبيق)

وشكرا

#8

منور أخي مادي

و سوف نتابع دروسك أخي الكريم

و الله يعاون

#9

بسم الله الرحمن الرحيم

اخي العزيز مادي

كان شرحي السابق شرح سريع يعني غير مفصل

واما عن block

فهي تنقسم الى اقسام اقسام الأيقاف الأشتراطيه

والأيقاف بواسطة النقطة الحمراء

وعندما تريد ايقاف البرنامج عن تكملة الأوامر المتبقية ممكن ذلك عن طريق end

وتقبل تحياتي اخوك SUM

#10

من كتاب ماركو كانتو: أساسي باسكال

** التعبيرات والعامِلات

لا توجد قاعدة عامة لبناء التعبيرات expressions ، حيث تعتمد اساسا على العامِلات التي تستخدم، و التي لباسكال العديد منها. هناك المنطقي logical والحسابي arithmetic والبولي Boolean والعلائقي relational ، و عاملات الفئة set، بالاضافة الى عدد آخر. يمكن استعمال التعبيرات لتحديد القيمة التي ستخصص للمتغير، او لحساب المحدد parameter التابع لوظيفة او اجراء، او لاختبار شرط. و قد تتضمن التعبيرات استدعاء وظائف ايضا. في كل مرة تقوم فيها باجراء عملية على قيمة في معرّف، و ليس استعمال المعرف في حد ذاته، فان هذا يعدّ تعبيرا .

تعد التعبيرات امرا شائعا في لغات البرمجة. التعبير هو أي توليفة من الثوابت constants ، المتغيرات، القيم الحرفية literal ، عاملات، و نتائج الوظائف. التعبيرات يمكن ايضا تمريرها الى المحددات القيمية value parameters في الاجراءات و الوظائف، و لكن ليس دائما الى المحددات المرجعية reference parameters (التي تحتاج الى قيمة يمكن تخصيصها).

** العامِلات و أسبقيتها

فيما يلي قائمة بعاملات اللغة، مجمعة حسب الأسبقية

1- عاملات أحدادية (أسبقية عليا)

@ عنوان المتغير أو الوظيفة (ترجّع مؤشّر)

not بولي أو ما يخص الجزيئات

2- العاملات الضربية و ما يخص الجزئيات

* ضرب حسابي أو تقاطع فئة

/ تقسيم نقطة عائمة

div تقسيم عدد صحيح

mod البواقي (باقي تقسيم عدد صحيح)

as تلبيس نوع آمن (RTTI)

and بولي أو ما يخص الجزيئات

shl ازاحة لليسار فيما يخصّ الجزئيات

shr ازاحة لليمين فيما يخصّ الجزئيات

3- العاملات الجمعية

+ جمع حسابي، اتحاد فئة، ربط جمل، اضافة رصيف مؤشّر

- طرح حسابي، طرح وتخالف فئة، طرح صف مؤشّر

or بولي أو ما يخص الجزيئات

xor بولي أو ما يخص الجزيئات

4- عاملات العلاقة والمقارنة (أسبقية دنيا)

= اختبار مساواة

<> اختبار عدم مساواة

< اختبار أقل من

> اختبار اكبر من

<= اختبار أقل من أو يساوي، أو فئة فرعية من فئة

>= اختبار أكبر من أو يساوي، أو فئة عليا تعلو فئة

in اختبار اذا ما عنصر عضو في فئة

is اختبار توافقية نوع لكائن(عامل RTTI آخر)

** عاملات الفئة

عاملات الفئة تتضمن اتحاد union (+)، طرح difference (-)، تقاطع intersection ( * )، اختبار عضوية membership (in)، بالإضافة الى مجموعة من العاملات العلائقية. لاضافة عنصر لمجموعة، يمكنك جعل اتحاد فئةة مع آخرى تملك فقط العنصر الذي تحتاجه. فيما يلي مثال بدلفي له علاقة بنمط الخطّ font styles:

[l]Style := Style + [fsBold];[/l]

[l]Style := Style + [fsBold, fsItalic] - [fsUnderline];[/l]

وشكرا

madi

#11

المتغيرات

تتطلّب دلفي ان تكون كل المتغيرات معرّفة قبل استخدامها. وحتى في الوقت الذي تعرّف فيه المتغير، يجب أن تحدّد نوع البيانات. ها هنا بعض نماذج تعريف المتغيرات:

var

Value: Integer;

  IsCorrect: Boolean;

  A, B: Char;

المصطلح var يمكن استخدامه في اماكن مختلفة في الكود، كأن يكون في بداية توليف وظيفة أو اجراء، او ان يتم تعريف المتغيرات محليا local في الروتين ، أو داخل الوحدة لتعريف متغيرات جامعة global. بعد مصطلح var تأتي قائمة اسماء المتغيرات، متبوعة بشارحة واسم نوع البيانات. يمكنك كتابة اكثر من اسم متغير واحد في السطر الواحد، كما هو في آخر تعليمة أعلاه.

حالما تقوم بتحديد متغير من نوع ما، تستطيع ان تقوم فقط بمباشرة العمليات الداعمة لنوع بياناته. على سبيل المثال، يمكنك استعمال القيمة البولية للاختبار و القيمة الصحيحة في التعبير الرقمي.

باستخدام تخصيصات بسيطة، نستطيع كتابة التوليف التالي:

Value := 10;

IsCorrect := True;

لكن التعليمة التالية ليست صحيحة، لأن المتغيرين يملكان نوع بيانات مختلف

Value := IsCorrect; // error

اذا حاولت تحويل هذا التوليف، فان دلفي تقوم باصدار خطأ تحويل رفق هذا التوضيح: Incompatible types: 'Integer' and 'Boolean'. عادة، مثل هذه الأخطاء هي أخطاء برمجية، لأنه لامعنى لتخصيص قيمة True أو False لقيم من نوع بيانات صحيح. يجب أن لا تلوم دلفي على مثل هذه الأخطاء. هي فقط تنبهك لوجود خطأ ما في التوليف.

بالطبع، غالبا مايمكن تبديل قيمة متغير من نوع بيانات الى نوع مختلف. في بعض الحالات، هذا التبديل يكون آليا، لكن عادة ما تحتاج الى استدعاء وظائف محددة في النظام لتغيير التمثيل الداخلي للبيانات.

تستطيع في دلفي ان تخصص قيمة تمهيدية لمتغير جامع global variable أثناء تعريفك له. مثلا، تستطيع كتابة:

var

Value: Integer = 10;

  Correct: Boolean = True;

تقنية التمهيد initialization هذه تصلح فقط للمتغيرات الجامعة، وليس للمتغيرات المعرفة داخل نطاق اجراء أو مسار.

الثوابت

تسمح دلفي ايضا بتعريف ثوابتا constants لتسمية القيم التي لاتتغير خلال عمل البرنامج. لتعريف ثابت لاتحتاج لتحديد نوع البيانات، فقط تخصيص قيمة ابتدائية. المحوّل سيتفحّص القيمة وآليا يستخدم نوع بياناته المناسب. هنا بعض امثلة التعريفات:

const

  Thousand = 1000;

  Pi = 3.14;

PName = 'Open';

يقرر دلفي نوع البانات للثابت بناء على قيمته. في المثال أعلاه، الثابت Thousand يفترض ان يكون من نوع صحيح صغير SmallInt ، اصغر نوع صحيح يمكنه احتواء القيمة. اذا اردت الطلب من دلفي استخدام نوع محدد؛ يمكنك ببساطة اضافة اسم النوع في التعريف، كما هو في:

const

  Thousand: Integer = 1000;

عندما تقوم بتعريف ثابت، يستطيع المحوّل أن يختار بين أن يخصص موقعا في الذاكرة للثابت، و يحفظ فيه قيمته، أو أن ينسخ قيمته الحقيقية في كلّ مرة يتم فيها استخدامه فيها

وشكرا

مــــMADIــــدي

#12

المرجع

كتاب ماركو كانتو

أنواع بيانات جديدة

إن أحد أعظم الأفكار التي قدمتها لغة دلفي هي القدرة على تحديد أنواع بيانات جديدة في البرنامج. يستطيع المبرمجون تحديد أنواع بيانات خاصة بهم بواسطة مشيّدات النوع type constructors، مثل أنواع المدى الفرعي subrange، نوع مصفوفة array، نوع تسجيلة record، نوع سردي enumerated، نوع مؤشّر pointer ، ونوع فئة set. أكثر أنواع البيانات المحددة بالمستعمل أهمية هي الطبقة أو الفصيلة class، و التي هي جزء من اضافات الاتجاه الكائني object-oriented في باسكال،

الأنواع المسماة وغير المسماة

هذه الأنواع يمكن إعطاؤها اسما للرجوع اليه لاحقا أو أن تطبّق على المتغيرات مباشرة. عندما تعطي اسما لنوع، يجب أن توفّر مساحة خاصة في التوليف، مثل الآتي:

type

  // subrange definitionتعريف نطاق 

  Uppercase = 'A'..'Z';



  // array definition تعريف مصفوفة 

  Temperatures = array [1..24] of Integer;



  // record definition  تعريف سجل او هيكل بيانات  Strucure

  Date = record

    Month: Byte;

    Day: Byte;

    Year: Integer;

  end;



  // enumerated type definition  المتعددات 

  Colors = (Red, Yellow, Green, Cyan, Blue, Violet);



  // set definition   فئات 

  Letters = set of Char;

ويمكن تعريف متغير من غير تسمية صريحة للنوع، كما هو في التوليف التالي

var

  DecemberTemperature: array [1..31] of Byte;

  ColorCode: array [Red..Violet] of Word;

  Palette: set of Colors;

ملاحظة:

عموما يجب عليك أن تتجنّب استخدام الأنواع غير المسمّاة unnamed مثل التوليف السابق، و ذلك لأنك لن تستطيع أن تمرّرها كمحدّدات الى الإجرائيات، أو أن تقوم بتصريح متغيّرات أخرى من نفس النوع. إن قواعد توافقية النوع في باسكال تعتمد في الواقع على أسماء الأنواع، و ليس على ما تم تحديده فعليا من أنواع. إن متغيّرين من نوعين متطابقين لايعتبران متوافقين، إلا إذا كانا نوعاهما يحملان نفس الإسم حرفيا، أما الأنواع غير المسمّاة فإنها تُعطى أسماء داخلية من قبل المجمّع compiler. حاول أن تتعوّد على عمليات تحديد نوع البيانات في كل مرّة تحتاج فيها إلى متغير مركب و غير بسيط،

امتلة

أنواع مدى فرعي

نوع المدى الفرعي subrange يحدد مدىً من القيم داخل نوع مدى آخر (من هنا اسم مدى فرعي). يمكنك تحديد مدى فرعي لنوع صحيح، من 1 إلى 10 او من 100 إلى 1000، أو تستطيع ان تحدد مدى فرعي من نوع حرف Char، كما في:

type

  Ten = 1..10;

  OverHundred = 100..1000;

  Uppercase = 'A'..'Z';

تحديد المدى الفرعي، لا تحتاج إلى تحديد اسم النوع الأساسي. أنت تحتاج فقط إلى تقديم ثابتين من نفس ذلك النوع. النوع الأصلي يجب أن يكون من نوع تراتبي ordinal، و النوع الناتج سوف يكون نوعا تراتبيا آخر.

عندما تكون قد حدّدت مدى فرعيا، يمكنك رسميا أن تخصص قيمة داخل ذلك المدى. هذا التوليف يعتبر صحيحا

var

  UppLetter: UpperCase;

begin

  UppLetter := 'F';

ولكن هذا ليس كذلك:

var

  UppLetter: UpperCase;

begin

  UppLetter := 'e'; // compile-time error

كتابة التوليف السابق ينتج عنه خطأ في زمن التجميع compile-time error بالرسالة التالية:، "Constant expression violates subrange bounds." ("تعبير لثابت يتخطّى حدود المدى."). أما إذا كتبت بدلا من ذلك التوليف التالي:

var

  UppLetter: Uppercase;

  Letter: Char;

begin

  Letter :='e';

  UppLetter := Letter;

فإن دلفي ستقوم بتجميعه. و لكن في زمن التشغيل run-time ، و إذا قمت بتمكين خيار المجمّع لتفحّص المدى Range Checking فستحصل على رسالة خطأ Range check error. (تمكين الخيار من خلال مربع Project Options ثم صفحة Compiler).

الأنواع السردية

تشكّل الأنواع السردية enumerated نوعا تراتبيا آخرا محددة بالمستعمل. فبدلا من الإشارة إلى مدى من نوع موجود، فإنك في السردية تقوم بعرض القيم المحتملة للنوع. بمعنى آخر، السردية هي قائمة بالقيم. فيما يلي بعض الأمثلة:

type

  Colors = (Red, Yellow, Green, Cyan, Blue, Violet);

  Suit = (Club, Diamond, Heart, Spade);

كلّ قيمة في القائمة لها ما يصاحبها من ترتيب ordinalty، بدءاً من الصفر. عندما تطبق وظيفة ord على على قيمة من نوع سردي، تتحصّل على نفس هذه القيمة المبتدئة بصفر. مثلا، Ord (Diamond) ترجع 1.

مكتبة المكوّنات المرئية VCL (Visual Component Library) في دلفي تستخدم الأنواع السردية في عدّة أماكن. مثال ذلك، نمط الحدود لنموذج form معرّف كالتالي:

type

  TFormBorderStyle = (bsNone, bsSingle, bsSizeable,

    bsDialog, bsSizeToolWin, bsToolWindow);

عندما تكون السِمة property قيمتها سردية، عادة ما تختار من قائمة القيم المعروضة في معاين الكائنات Object Inspector في الدلفي ,

في المتال السابق كانت القائمة لا حد خواص الفورم وهي شكل الفورم . و هناك خواص اخرى ايضا هي عبارة عن قوائم سردية متل

خاصية ALign و WindowState و غيرها .

نوع فئة

أنواع الفئة set تشير إلى مجموعة من القيم. فهي صفّ من القيم المحتملة ذات نفس النوع التراتبي ordinal الذي للفئة. هذه الأنواع التراتبية عادة ما تكون محدودة، و غالبا ما يتم تمثيلها بسردية enumeration أو مدى فرعي subrange. إذا أخذنا المدى الفرعي 1..3، فإن القيم المحتملة للفئة التي ستبنى على هذا المدى سوف تتضمن إما: فقط 1، فقط 2، فقط 3، كلا 1 و 2، كلا 1 و 3، كلا 2 و 3، كل القيم الثلاث، أو لا واحدة منهم.

أي متغيّر عادة ما يضّم أحد هذه القيم المحتملة من المدى الذي يسمح به نوعه. أما المتغير الذي من نوع فئة، يمكنه أن يحوي أكثر من قيمة واحدة، فقد يحوي لا شيء، واحدة، إثنتان، ثلاثة، أو قيم أكثر ضمن المدى. بل يمكنه أن يتضمن كلّ القيم. ها هنا مثال عن فئة:

type

  Letters = set of Uppercase;

الان يمكنني أت أعرف متغيرا من هذا النوع و أخصص له بعض القيم حسب النوع الأصلي. للإشارة إلى بعض القيم في فئة، تقوم بكتابة سردا مفصول بفاصلة comma-separated، و محصورا بين قوسين مربعين brackets. التوليف التالي يعرض تخصيصات لمتغير: بقيم متعددة، بقيمة واحدة، و بقيمة فارغة:

var

  Letters1, Letters2, Letters3: Letters;

begin

  Letters1 := ['A', 'B', 'C'];

  Letters2 := ['K'];

  Letters3 := [];

في دلفي، تستخدم الفئة عموما للإشارة إلى قيم غير حصرية. مثلا، سطرا التوليف التاليان (و هما جزء من مكتبة دلفي) يعرّفان سردا enumeration من الأيقونات المحتملة لإطار نافذة window ثم ما يوافق ذلك من نوع فئة:

type

  TBorderIcon = (biSystemMenu, biMinimize, biMaximize, biHelp);

  TBorderIcons = set of TBorderIcon;

في الواقع، عند التعامل مع معاين الكائنات Object Inspector ستجد

بعض منها وتميزه بوجود علامة + , ولكي تعرض عناصره تضغط بالماوس على علامة + , فتفتح لك قائة فرعية و تصبح علامة + علامة - ,

سِمة أخرى porperty مبنية على نوع فئة و هي نمط الخط font style. القيم المحتملة تشير لخط داكن bold، مائل italic، تحته خط underline، و خط مقطوع strikethrough. بالطبع نفس الخط قد يكون مائلا و داكنا معا، أو بلا أي نمط، أو أن يملك أنماط الخط كلّها. لهذا السبب تم تعريف نمط الخط كفئة. و يمكنك تخصيص قيم لهذه الفئة في توليف برنامج كالتالي:

Font.Style := []; // no style

Font.Style := [fsBold]; // bold style only

Font.Style := [fsBold, fsItalic]; // two styles

يمكنك اجراء عمليات على الفئة بطرق مختلفة، بما في ذلك جمع متغيرين من نفس نوع الفئة (لنكون أكثر دقّة، حساب اتحاد فئتين):

Font.Style := OldStyle + [fsUnderline]; // two sets

أنواع مصفوفة

أنواع مصفوفة Array types تحدد قوائما بعدد ثابت من العناصر من نوع محدد. أنت ستستعمل عادة دليلا index بين قوسين مربعين للوصول إلى أحد عناصر المصفوفة. الأقواس المربعة تستعمل أيضا لتحديد القيم المحتملة لعدد العناصر عند تعريف المصفوفة. مثلا، يمكنك تحديد مجموعة من 24 صحيحا بالتوليف التالي:

 

type

  DayTemperatures = array [1..24] of Integer;

عند تعريف المصفوفة، تحتاج إلى تمرير نوع مدى فرعي subrange بين قوسين مربعين، أو تحديد نوع مدى فرعي جديد خاص باستخدام ثابتين constant من نوع تراتبي. المدى الفرعي هذا يحدد الأدلة indexes المسموح بها في المصفوفة. و حيث انك ستحدد كل من الدليل الأعلى و الدليل الأدنى في المصفوفة، فإن الأدلة لا حاجة لها بأن تبدأ بصفر zero-based، عكس الحال في س، و س++، و جافا، و لغات برمجة أخرى.

و حيث أن أدلة المصفوفة مبنية على مدى فرعي subrange، يمكن لدلفي أن تتفحّص مداها كما رأينا سابقا. فأي ثابت خارج النطاق في مدى فرعي سينتج خطأ عند زمن التجميع؛ كما أن أي دليل خارج النطاق يستخدم في زمن التشغيل ينتج عنه خطأ زمن التشغيل، في حالة تمكين الخيار ذو العلاقة في المجّمع.

باستخدام تعريف المصفوفة أعلاه، يمكنك جعل قيمة المتغير DayTemp1 من نوع DayTemperatures كالتالي:

 



type

  DayTemperatures = array [1..24] of Integer;



var  

  DayTemp1: DayTemperatures;

  

procedure AssignTemp;  

begin  

  DayTemp1 [1] := 54;

  DayTemp1 [2] := 52;

  ...

  DayTemp1 [24] := 66;

  DayTemp1 [25] := 67; // compile-time error

قد يكون للمصفوفة أكثر من بعد واحد، كما في المثال التالي:

 

type

  MonthTemps = array [1..24, 1..31] of Integer;

  YearTemps = array [1..24, 1..31, Jan..Dec] of Integer;

نوعي المصفوفة بنيا على النوع الأساسي نفسه. يمكنك تعريفهما باستخدام أنواع البيانات السابقة، كما في التوليف التالي:

type

  MonthTemps = array [1..31] of DayTemperatures;

  YearTemps = array [Jan..Dec] of MonthTemps;

هذا التعريف يقلب تريب الأدلّة كما هو أعلاه، لكنّه أيضا يسمح بتخصيص كُتل كاملة فيما بين المتغيرات. مثلا، التعليمة التالية تنسخ درجات حرارة temperatures شهر يناير إلى فبراير:

var

  ThisYear: YearTemps;

begin

  ...

  ThisYear[Feb] := ThisYear[Jan];

يمكنك أيضا تعريف مصفوفة تبدأ بصفر zero-based ، نوع مصفوفة حدّها الأدني يساوي صفر. عموما، استخدام حدّين منطقيين أكثر يعدّ ميزة، حيث لا تضطر إلى استخدام الدليل 2 للوصول إلى العنصر 3، و هكذا. إلا أن ويندوز وبصورة ثابتة تستخدم مصفوفات تبدأ بصفر (لأنها مؤسسة على لغة س)، و مكتبة مكونات دلفي تتجه لفعل نفس الشيء.

إذا احتجت إلى الاشتغال على مصفوفة، يمكنك دائما اختبار حدّيها باستخدام الوظيفتين النمطيتين Low و High، و اللتين ترجعان الحدّ الأدنى والحدّ الأعلى. يُنصح بشدّة باستخدام Low و High عند التعامل مع المصفوفة، خاصة في الحلقات loops، ما دامتا تجعلان من التوليف غير محتاج لمعرفة نطاق المصفوفة مقدما. لاحقا يمكنك تغيير النطاق المعرّف لأدلة المصفوفة، و يبقى التوليف الذي يستعمل Low و High بدون تغيير و مستمرا في عمله. أما إذا كتبت حلقة loop مع تحديد صريح لنطاق المصفوفة، فستجد نفسك مضطرا لتحديث التوليف الخاص بالحلقة كلما تغيّر حجم المصفوفة. Low و High تجعلان من توليفك أكثر سهولة عند الصيانة و أكثر اعتمادية.

Record Types

نوع تسجيلة record types تحدّد مجموعة ثابتة من عناصر ذات أنواع مختلفة. كل عنصر، أو حقل field ، له نوعا خاصا به. تعريف نوع تسجيلة تعرض قائمة بكل هذه الحقول، تعطي لكل منها اسما لتستخدمه لاحقا من أجل الوصول إليه.

هنا عرضا بسيطا لتعريف من نوع تسجيلة، ثم تعريف لمتغير من هذا النوع، و بعض التعليمات التي تستخدم هذا المتغيّر:

 



type

  Date = record

    Year: Integer;

    Month: Byte;

    Day: Byte;

  end;

  

var

  BirthDay: Date;

  

begin

  BirthDay.Year := 1997;

  BirthDay.Month := 2;

  BirthDay.Day := 14;

Pointers

نوع مؤشّر pointer يحدّد متغيرا يحوي عنوان متغير آخر في الذاكرة ذو نوع بيانات محدد (أو نوع غير محدد). لذا فإن متغير المؤشر و بطريقة غير مباشرة يشير إلى قيمة. تعريف نوع مؤشّر لا يستلزم كلمة مفتاحية معينة، انه يستعمل حرفا خاصا بدلا من ذلك. الحرف أو الرمز الخاص هو علامة الادراج caret (^):

 

type

  PointerToInt = ^Integer;

حالما عرّفت متغيرا مؤشرا، يمكنك أن تخصص له العنوان الخاص بمتغير آخر من نفس النوع، باستخدام العامل @:

 



var

  P: ^Integer;

  X: Integer;

begin

  P := @X;

  // change the value in two different ways

  X := 10;

  P^ := 20;

عندما يكون لديك المؤشّر P، فإنه بواسطة التعبير P أنت تشير إلى موقع في الذاكرة يشير إليه المؤشر، و بواسطة التعبير P^ أنت تشير إلى المحتويات الفعلية في موقع الذاكرة هذا. لهذا السبب في التوليف السابق فإن P^ تطابق X .

بدلا من الإشارة إلى موقع ذاكرة موجود، يمكن للمؤشر أن يشير إلى مساحة جديدة في الذاكرة يتم تخصيصها بصورة حيّة (في منطقة من محيط الذاكرة) بواسطة الإجرائية New. في هذه الحالة، و عند إنتهاء حاجتك للمؤشر، عليك أيضا أن تتخلص من الذاكرة التي قمت بحجزها، بإستدعاء الوظيفة Dispose .

 



var

  P: ^Integer;

begin

  // initialization

  New (P);

  // operations

  P^ := 20;

  ShowMessage (IntToStr (P^));

  // termination

  Dispose (P);

end;

إذا كان المؤشر خاليا من أية قيمة، يمكنك تخصيص قيمة nil لا شيء له، بعدها تستطيع إختبار خلوّ المؤشر لمعرفة إذا ما هو حاليا يشير إلى قيمة. و هذا يستعمل عادة، لأن التأشير الخاطئ بمؤشر فارغ يسبّب انتهاكا لحرمة الدخول access violation. (أيضا يعرف بخطأ حماية عام general protection fault ، أو GPF) , فكتيرا ما تواجهك رسالة الحطاء

access violation at Address 055544888 in model

في نفس البرنامج يمكن أن تجد مثالا لكيفية الوصول الآمن للبيانات. في هذه الحالة الثانية تمّ تخصيص المؤشر لمتغير محلي موجود، و يمكن استخدامه بأمان، لكني أضفت إليه فحص أمان للتأكيد:

 

procedure TFormGPF.BtnSafeClick(Sender: TObject);

var

  P: ^Integer;

  X: Integer;

begin

  P := @X;

  X := 100;

  if P <>  nil then

    ShowMessage (IntToStr (P^));

end;

تعرّف دلفي أيضا نوع بيانات مؤشر تدلّ على مؤشرات بلانوع untyped (مثل void* في لغة س). إذا استخدمت مؤشرات بلا نوع يجب أن تستخدم GetMem بدلا من New. إجرائية GetMem مطلوبة في كل مرة يكون فيها حجم متغير الذاكرة المطلوب حجزه غير محدد.

.

 



procedure TFormGPF.BtnGpfClick(Sender: TObject);

var

  P: ^Integer;

begin

  P := nil;

  ShowMessage (IntToStr (P^));

end;

و شكرا

المرجع

كتاب ماركو كانتو

مــــMADIــــدي

#13

التعليمات البسيطة والمركبة

باسكال تكون بسيطة عندما لا تحتوي على أية تعليمات أخرى. كأمثلة على التعليمات البسيطة نجد تعليمات التخصيص assignment و استدعاءات الاجرائيات procedure calls. التعليمات البسيطة يتم الفصل بينها بفاصلة منقوطة semicolon :

X := Y + Z;  // assignment

Randomize;   // procedure call

عادة، تكون التعليمات جزءا من تعليمات مركبة، مؤمرة بعلامات البداية begin و النهاية end. التعليمة المركبة يمكن أن تظهر في مكان تعليمة باسكال عامة. ها هنا مثال:

 



begin

  A := B;

  C := A * 2;

end;

الفاصلة المنقوطة بعد اخر تعليمة قبل end ليست ضرورية. مثل التالي:

 



begin

  A := B;

  C := A * 2

end;

كلا النسختين صحيحتين. النسخة الأولى لها فاصلة منقوطة غير مجدية (لكنها لاتؤذي). هذه الفاصلة المنقوطة، في الواقع، هي تعليمة فارغة؛ تعليمة بدون توليف code . لا حظ هذا، أحيانا، التعليمات الفارغة يمكن استخدامها داخل الحلقات loops أو في حالات خاصة.

تعليمات التخصيص

التخصيصات assignments في باسكال تستخدم رمزي شارحة يساوي، ترميز غريب بالنسبة للمبرمجين الذين اعتادوا لغات اخرى. الرمز = و الذي يستعمل للتخصيص في بعض اللغات الأخرى، يستعمل في باسكال لاختبار المساواة equality.

التعليمات الشرطية

التعليمة الشرطية conditional statement تستعمل لتنفيذ إحدى التعليمات التي تتضمنها أو عدم تنفيذ و لا واحدة منها. بالاعتماد على شيء من الاختبار. يوجد شكلين من التعليمات الشرطية: تعليمات if و تعليمات case.

تعليمات If

تعليمة if يمكن استخدامها لتنفيذ تعليمة أخرى فقط إذا تحقق شرط معين (if-then)، أو للإختيار بين بديلين (if-then-else). يتم وصف الشرط بتعبير بولي boolean. مثال دلفي بسيط سيوضح كيفية كتابة تعليمات شرطية. أولا قم بإنشاء تطبيق application جديد، ثم ضع على النموذج form خانتي فحص check box و أربعة أزرار buttons . لا تغيّر أسماء الأزرار و خانات الفحص، قم بضغط مزدوج على كل زرّ لإضافة مناول handler للحدث OnClick الخاص بكل زرّ، ها هنا تعليمة if بسيطة للزر الأول:

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  // simple if statement

  if CheckBox1.Checked then

    ShowMessage ('CheckBox1 is checked')

end;

عندما تضغط على الزر، إذا كانت خانة الفحص الأول لديها علامة فحص، سيقوم البرنامج بعرض رسالة بسيطة. لقد استعملت وظيفة ShowMessage لأنها أسهل وظيفة في دلفي يمكن استعمالها لإظهار رسالة قصيرة للمستخدم .

إذا ضغطت على الزر و لم يحدث شيء، فهذا معناه أن خانة الفحص غير معلّمة. في مثل هذه الحالة، قد يكون من المستحسن جعل الأمر أكثر صراحة، كما هو في التوليف الخاص بالزرّ الثاني، و الذي يستعمل تعليمة if-then-else.

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  // if-then-else statement 



  if CheckBox2.Checked then

    ShowMessage ('CheckBox2 is checked')

  else

    ShowMessage ('CheckBox2 is NOT checked');

end;

لاحظ أنه لايمكنك وضع فاصلة منقوطة بعد التعليمة الأولى و قبل مصطلح else، و إلا فإن المحوّل سيصدر خطأ جملة syntax error. إن تعليمة if-then-else في الواقع هي تعليمة واحدة، لذا لا يمكنك وضع فاصلة منقوطة في وسطها.

تعليمة if يمكن لها أن تكون أكثر تعقيدا. فالشرط يمكن تحويله إلى سلسلة من الشروط (باستخدام and و or و not)، أو ان تعليمة if تتفرع عنها تعليمة if أخرى. الزرّين الأخيرين في مثال IfTest يعرضان هاتين الحالتين:

 

procedure TForm1.Button3Click(Sender: TObject);

begin

  

  // statement with a double condition

    

  if CheckBox1.Checked and CheckBox2.Checked then

    ShowMessage ('Both check boxes are checked')

end;





procedure TForm1.Button4Click(Sender: TObject);

begin

  // compound if statement

  if CheckBox1.Checked then

    if CheckBox2.Checked then

      ShowMessage ('CheckBox1 and 2 are checked')

    else

      ShowMessage ('Only CheckBox1 is checked')

  else

    ShowMessage (

      'Checkbox1 is not checked, who cares for Checkbox2?')

end;

أنظر إلى التوليف جيدا و شغل البرنامج لترى ما إذا فهمت كل ما سبق. عندما يكون لديك شك حول بناء برمجي، فإن كتابة برنامج بسيط جدا مثل هذا يمكن أن يساعدك تلتعلم الكثير. بإمكانك اضافة المزيد من خانات التفحص و زيادة تعقيد هذا البرنامج البسيط، و إجراء أي اختبار ترغب به.

الآن لحض الثلات طرق التالية التي تعطي نفس النتيجة , ولكن بطرق مختلفة , افرض أن لديك رقم صحيح و تريد أن تختبر ادا كان أحد تلاث قيم , كالتالي

1-

 

 variable in [21, 24, 29] then

begin

 .. do whatever

end;

2-

 

if variable = 21 then

begin

 .. do whatever

end

else if variable = 24 then

begin

 .. do whatever

end

else if variable = 29 then

begin

 .. do whatever

end;

3

 

if ((variable = 21) or 

   (variable = 24) or 

   (variable = 29)) then

begin

 .. do whatever

end;

تعليمات Case

إذا ما أضحت تعليمات if لديك أكثر تعقيدا، يمكنك استبدالها في أية لحظة بتعليمات case. تعليمة case عبارة عن تعبير يستخدم لاختيار قيمة، قائمة بقيم محتملة، أو مدى من القيم. هذه القيم هي ثوابت constants، و يجب أن تكون فريدة ومن نوع تراتبي ordinal. أحيانا، قد يوجد بها تعليمة else و التي يتم تنفيذها إذا لم تتوافق أي من الاحتمالات مع القيمة المعطاة. فيما يلي مثالين بسيطين:

 



case Number of

  1: Text := 'One';

  2: Text := 'Two';

  3: Text := 'Three';

end;

المتال التاني

 

case MyChar of

  '+' : Text := 'Plus sign';

  '-' : Text := 'Minus sign';

  '*', '/': Text := 'Multiplication or division';

  '0'..'9': Text := 'Number';

  'a'..'z': Text := 'Lowercase character';

  'A'..'Z': Text := 'Uppercase character';

else

  Text := 'Unknown character';

end;

ملاحظة:

لا تملك الدلفي تعليمات مثل endif أو endcase. إذا كان لتعليمة if حيز begin-end، فإن نهاية هذا الحيز يحدد نهاية التعليمة. بالمقابل، تعليمة case تنتهي دائما بكلمة end. كل تعليمات end هذه، التي غالبا ما تكون واحدة فوق الأخرى، يمكن أن تجعل من التوليف صعب التتبع. فقط من خلال تتبع الهوامش يمكن معرفة تبعية كل end و لأية تعليمة. الطريقة العامة المتّبعة لحل هذه المشكلة و لجعل التوليف مفهوما أكثر هو في اضافة ملاحظة بعد تعليمة end تشير إلى تبعيتها، كما في:

وشكرا

مــــMADIــــدي

#14

الحلقات في دلفي

للغة دلفي التعليمات التكرارية النمطية التي لمعظم لغات البرمجة، يتضمن هذا تعليمات for، و while، و repeat .

حلقة For

حلقة for في دلفي مبنية بصورة مقيدة على عداد counter، و الذي يمكن زيادته أو تخفيضه في كل مرة يتم تنفيذ الحلقة. فيما يلي مثال بسيط لحلقة for مستخدمة لإضافة أول عشرة أرقام.

 

var

  K: Integer;

begin

  K := 0;

  for I := 1 to 10 do

    K := K + I;

نفس المثال كان يمكن كتابته باستخدام عداد معكوس:

 

begin

  K := 0;

  for I := 10 downto 1 do

    K := K + I;

حلقة for في دلفي أقل مرونة مقارنة بلغات أخرى (ليس بالإمكان تحديد معدّل زيادة إلا بواحد)، لكنها بسيطة و سهلة الفهم. إذا اردت اختبار شرط بتشعب أكبر، أو أردت ايجاد عداد بمواصفات خاصة، فأنت بحاجة إلى استخدام تعليمات while أو repeat ، عوضا عن حلقة for.

تعليمات While و Repeat

الفرق بين حلقة while-do و حلقة repeat-until هو أن التوليف code داخل تعليمة repeat ينفّذ دائما، مرة واحدة على الأقل. تستطيع بسهولة فهم السبب بالإطّلاع على المثال البسيط:

 

while (I < 100) and (J < 100) do

begin

  // use I and J to compute something...

  I := I + 1;

  J := J + 1;

end;

Repate

 



repeat

  // use I and J to compute something...

  I := I + 1;

  J := J + 1;

until (I > 100) or (J > 100);

إذا كانت القيمة الإبتدائية في I أو J أكبر من 100، فإن التعليمات داخل حلقة repeat-until سيتم تنفيذها مرة على كل حال.

الفرق الرئيسي الاخر بين هذين الحلقتين هو أن حلقة repeat-until لديها شرط محجوز reserved . الحلقة سيتم تنفيذها حتى اللحظة التي لا يتم فيها تحقيق الشرط. عندما يتحقق الشرط، تتوقف الحلقة. هذا عكس حلقة while-do ، التي تنفذ ما دام الشرط موجبا. لهذا السبب عليّ أن أعكس الشرط في التوليف أعلاه للحصول على تعليمة مشابهة.

مثال عن الحلقات

لإستكشاف تفاصيل الحلقات، دعنا نستعرض مثال دلفي بسيط. برنامج Loops يبرز الفرق بين حلقة بعداد ثابت و حلقة بعدّاد عشوائي تقريبا. إبدأ بمشروع project جديد، ضع مربع قائمة list box و زرّيّن على النموذج form الرئيسي، قم بإعطاء الزرين إسمين مناسبين (BtnFor و BtnWhile) و ذلك بتوصيف سِمة Name فيهما بواسطة معاين الكائنات Object Inspector.

 

object Form1: TForm1

  Caption = 'Loops'

  object ListBox1: TListBox ...

  object BtnFor: TButton

    Caption = '&For'

    OnClick = BtnForClick

  end

  object BtnWhile: TButton

    Caption = '&While'

    OnClick = BtnWhileClick

  end

end

الآن يمكنا اضافة بعض التوليف لحدثي OnClick في الزرين. الزر الأول به حلقة for بسيطة لعرض قائمة من الأرقام، قبل تنفيذ هذه الحلقة، التي تضيف عددا من الجمل إلى سِمة Items في مرّبع القائمة، تحتاج لتصفية محتويات القائمة نفسها Clear.

procedure TForm1.BtnForClick(Sender: TObject);

var

I: Integer;

begin

ListBox1.Items.Clear;

for I := 1 to 20 do

Listbox1.Items.Add ('String ' + IntToStr (I));

end;

التوليف المربوط بالزر الثاني أكثر تعقيدا نوعا ما. ففي هذه الحالة، توجد حلقة while قائمة على عدّاد، يتم زيادته عشوائيا. لإنجاز ذلك، قمت باستدعاء الإجرائية Randomize، والتي تقوم بإعادة تهيئة مولد الرقم العشوائي، و وظيفة Random بنطاق مداه 100. نتيجة هذه الوظيفة هو رقم بين 0 و 99، يتم إختيارها عشوائيا. سلسلة الأرقام العشوائية تتحكم في عدد مرّات تنفيذ حلقة while.

procedure TForm1.BtnWhileClick(Sender: TObject);

var

I: Integer;

begin

ListBox1.Items.Clear;

Randomize;

I := 0;

while I < 1000 do

begin

I := I + Random (100);

Listbox1.Items.Add ('Random Number: ' + IntToStr (I));

end;

end;

كل مرة تضغط على زر while، تختلف الأرقام، لأنها تعتمد على مولد لرقم عشوائي.

لاحظ أنه ليس فقط الأرقام التي تم توليدها مختلفة، بل أيضا عدد العناصر مختلف. حلقة while هذه تُنتج عددا عشوائيا من العناصر. إذا ضغطت على زرّ while عدة مرّات، سوف ترى أن القائمة لديها عدد أسطر مختلف.

ملاحضة

يمكنك تحويل التدفق المعتاد لتنفيذ الحلقة باستخدام اجرائيات النظام Break و Continue. الأول يستخدم لعرقلة الحلقة؛ أما الثاني فيُستخدم للقفز مباشرة إلى اختبار الحلقة أو إلى مزيد العدّاد، بحيث يعيد الاستمرار مع الدورة التالية للحلقة (ما لم يكن الشرط صفرا أو أن العدّاد قد بلغ حدّه الأعلى). أيضا توجد الإجرائيتان Exit و Halt، تسمح لك الأولى بالخروج حالا من الوظيفة أو الإجرائية التي فيها، والثانية تنهي عمل البرنامج.

وشكرا

مــــMADIــــدي

#15

تعليمة With

أخر نوع من تعليمات دلفي سنقوم بالتركيز عليه هي تعليمة with ، و التي تعد مميزة في هذه اللغة البرمجية (و تم إدخالها مؤخّرا في فيجوال بيسك) و مفيدة جدا في البرمجة بدلفي.

تعليمة with ليس إلا اختصار shorthand. عندما تحتاج إلى الاشارة الى متغير نوع تسجيلة record (أو كائن object)، فبدلا من تكرار اسمه في كل مرّة، يمكنك استخدام تعليمة with . مثال ذلك، التوليف التالي:

 

type

  Date = record

    Year: Integer;

    Month: Byte;

    Day: Byte;

  end;



var

  BirthDay: Date;



begin

  BirthDay.Year := 1997;

  BirthDay.Month := 2;

  BirthDay.Day := 14;

باستعمال تعليمة with، بامكاني تحسين الجزء الأخير من التوليف، كالتالي:

 

begin

  with BirthDay do

  begin

    Year := 1995;

    Month := 2;

    Day := 14;

  end;

هذا الاسلوب يمكن استخدامه في برامج دلفي للإشارة الى المكونات components و أنواع الطبقات class الأخرى. مثلا، يمكننا إعادة كتابة الجزء الأخير من آخر مثال، مثال Loops، باستخدام تعليمة with لمناولة العناصر items في القائمة:

 

procedure TForm1.WhileButtonClick(Sender: TObject);

var

  I: Integer;

begin

  with ListBox1.Items do

  begin

    Clear; // shortcut

    Randomize;

    I := 0;

    while I < 1000 do

    begin

      I := I + Random (100);

      // shortcut:

      Add ('Random Number: ' + IntToStr (I));

    end;

  end;

end;

عندما تتعامل مع المكونات components أو الطبقات classes في باسكال عموما، تسمح لك تعليمة with بالاستغناءعن كتابة بعض التوليف، خاصة بالنسبة للحقول المتفرعة. مثلا، لنفترض انك تريد تغيير حجم و لون قلم الرسم لنموذج form. يمكنك كتابة التوليف التالي:

 

Form1.Canvas.Pen.Width := 2;

Form1.Canvas.Pen.Color := clRed;

و لكنه بالتأكيد سيكون الأمر أسهل لو كتبت التوليف التالي:

 

with Form1.Canvas.Pen do

begin

  Width := 2;

  Color := clRed;

end;

عندما تقوم بكتابة توليفا متشعبا، يمكن لتعليمة with أن تكون فعالة و تعفيك من تعريف بعض المتغيرات المؤقتة، و لكنها لا تخلو من العيوب. فبامكانها أن تجعل من التوليف أقل مقروئية، خاصة عندما تتعامل مع كائنات مختلفة لكن لديها سمات متشابه أو متطابقة.

يوجد أيضا عيب آخر، و هو ان استعمال تعليمة with قد تسمح بأخطاء منطقية شفافة في التوليف يصعب على المجمع تحسسها. مثال ذلك:

 

with Button1 do

begin

  Width := 200;

  Caption := 'New Caption';

  Color := clRed;

end;



[CODE] 



هذا التوليف يغير من عنوان Caption و عرض With الزر، و لكنه يؤتر في سِمة اللون Color للشكل Form ، و ليس في الزر! سبب هذا أن المكوّن TButton ليس لديه سِمة Color، و حيث أن التوليف يتم تنفيذه داخل كائن form نموذج الذي لديه مثل هذه السِمة فإن الافتراض الأول يتجه له مباشرة. بدلا من ذلك إذا كتبنا: 



[CODE] 

Button1.Width := 200;

Button1.Caption := 'New Caption';

Button1.Color := clRed; // error!

فإن المجمعCompiler الخاص بدلفي سيصدر خطأ.

يجب أن تتجنب الاستخدام المتعدد لتعليمات with ، مثل:

 

with ListBox1, Button1 do...

فالتوليف الذي سيتبعه سيكون غالبا غير مقروء و صعب التتبع، لأنه مع كل سِمة يتم تحديدها في هذا الحيّز تحتاج إلى استنتاج و معرفة المكون المقصود الذي تتبعه هذه السِمة، بالاعتماد على السِمات ذات العلاقة و ترتيب المكونات في تعليمة with.

وشكرا

مــــMADIــــدي

#16

ممتاز أخي madi فمواضعيك جداً قيمة :) نرجو من الاستمرار

#17

الف شكر لك اخي العزيز , وان شا الله الفائدة تعم . و الله الموفق للجميع .

الإجراءات والوظائف

فكرة أخرى مهمة ركزت عليها دلفي هي مفهوم الإجرائيات routine. مبدئيا هي سلسلة من التعليمات تحت اسم خاص غير مكرر، و التي يمكن تنشيطها في كل مرّة باستخدام اسمها. بهذه الطريقة تتجنب معاودة كتابة التعليمات مرة بعد أخرى، فتتحصّل على نسخة واحدة من التوليف يمكنك بسهولة تعديله لصالح كامل البرنامج .

في دلفي الإجرائية routine يمكن افتراضها بشكلين: إجراء procedure و وظيفة function. نظريا، الإجراء هو عملية تقوم أنت كمبرمج بسؤال الحاسب كي ينجزها، الوظيفة هي حسبة تردّ قيمة. هذا الفرق يؤكّده حقيقة أن الوظيفة لها نتيجة result، قيمة مسترجعة، بينما الإجراء ليس كذلك. كلا النوعين من الاجرائيات يكمن أن يكون لهما عدة محددات parameters، من أنواع بيانات تعطى لها.

عمليا، الفرق عموما بين الوظائف و الإجراءات محدود جدا: يمكنك استدعاء وظيفة لإنجاز عمل ما ثم تتخطّى النتيجة (التي قد تكون رمز خطأ اختياري أو ما شابه) كما بإمكانك إستدعاء إجراء يمرّر نتيجته ضمن محدداته.

هنا تعريفات لإجراء .

 

procedure Hello;

begin

  ShowMessage ('Hello world!');

end;

هنا تعريف دالتين من نفس الوظيفة، باستخدام صيغ مختلفة قليلا:

 

function Double (Value: Integer) : Integer;

begin

  Double := Value * 2;

end;





// or, as an alternative

function Double2 (Value: Integer) : Integer;

begin

  Result := Value * 2;

end;

في حالة الوضيفة Double تم استخدام اسم الوظيفة لارجاع القيمة .

ام في حالة الوضيفة Double2 فتم استخدام result بدلا من اسم الوظيفة من أجل تخصيص قيمة الوظيفة المرتجعة , هده العملية أصبحت شائعة جدا، و تنحى لجعل التوليف أكثر مقروئية،

الآن يمكننا العودة إلى مفهوم تغليف التوليف الذي أشرت إليه سابقا. عندما تستدعي وظيفة Double، أنت لا تحتاج إلى معرفة الخوارزمية التي أُستخدمت لتنفيذها. إذا وجدت لاحقا طريقة أفضل لمضاعفة الأرقام، يمكنك بسهولة تغيير توليف الوظيفة، لكن التوليف الذي قام بالإستدعاء سيبقى ثابتا .

نفس المفهوم يمكن تطبيقه على وظيفة Hello التالية , يمكننا تعديل مخرجات البرنامج بتغيير التوليف داخل هذه الوظيفة , متل يمكن تغيير العبارة التي سوف تنتج من 'Hello world! الى 'Hello Group!:

 

procedure Hello;

begin

  MessageDlg ('Hello world!', mtInformation, [mbOK]);

end;

حالما يتم تعريف هذه الإجرائات، يمكنك إستدعائهم مرة أو أكثر.

تستدعي الإجراء لجعله ينجز مهمته، و تستدعي الوظيفة لحساب القيمة.

متال :

ببساطة قم بوضع زرين على نافذة دلفي، قم بكتابة الاجراء hello تم

لمسة مزدوجة فوق كل زر وقت التصميم، و ستقوم بيئة دلفي IDE بتوليد ما يناسب من توليف داعم: الآن و ببساطة عليك ملء الأسطر بين begin و end. لتجميع التوليف تحتاج أيضا إلى إضافة خانة كتابة Edit للنافذة .

 



procedure Hello;

begin

  MessageDlg ('Hello world!', mtInformation, [mbOK]);

end;



procedure TForm1.Button1Click (Sender: TObject);

begin

  Hello;

end;



procedure TForm1.Button2Click (Sender: TObject);

var

  X, Y: Integer;

begin

  X := Double (StrToInt (Edit1.Text));

  Y := Double (X);

  ShowMessage (IntToStr (Y));

end

وشكرا

مــــMADIــــدي

#18

تابع الإجراءات والوظائف

عندما تستدعي إحدى وظائف أو إجراءات دلفي، أو أي مسار لمكون VCL، يجب أن تتذكر عدد و نوع المحددات. محرر دلفي يمكن أن يساعد باقتراحه لقائمة المحددات الخاصة بالوظيفة أو الإجراء بواسطة تلميحة محادية حالما تقوم بطباعة اسم الاجرائية و تفتح قوسا. هذه الخاصية تدعى Code Parameters و هي جزءا من تقنية Code Insight

المحددات بالاشارة reference

تسمح لك إجرائيات دلفي بتمرير المحددات parameter بقيمتها by value و بالإشارة by reference. افتراضيا المحددات يتم تمريرها بالقيمة: يتم نسخ القيمة في الصف stack و تقوم الإجرائيات باستخدام و معالجة النسخة، و ليست القيمة الأصلية.

تمرير المحدد بالإشارة يعني أن قيمته لايتم نسخها في الصف لدي الإجرائية (تجنب النسخ دائما يعني أن تنفيذ البرنامج يكون أسرع). بدلا من ذلك، البرنامج يشير إلى القيمة الأصلية، يحدث هذا أيضا في توليف الإجرائية. هذا يسمح للإجراء أو الوظيفة بأن تغير في قيمة المحدد. المحدد المرر بالإشارة يعبر عنه بالمصطلح var .

هذا الأسلوب موجود في معظم لغات البرمجة. هو ليس موجودا في س، و لكن تم ادخاله في س++، حيث تقوم باستعمال علامة & (تمرير بالإشارة). في فيجوال بيسك كل محدد لا يكون بصفة ByVal يتم تمريره بالإشارة.

هنا مثال لتمرير محدد بالإشارة باستخدام مصطلح var :

 

procedure DoubleTheValue (var Value: Integer);

begin

  Value := Value * 2;

end;

في هذه الحالة، المحدد تم استخدامه لغرضين، لتمرير قيمة للإجرائية و لإسترجاع القيمة الجديدة للتوليف الذي قام بالاستدعاء. عندما تكتب:

 

var

  X: Integer;

begin

  X := 10;

  DoubleTheValue (X);

فإن قيمة المتغير X تصبح 20، لأن الإجرائية تتعامل مع إشارة لموقع الذاكرة الأصلي ل X ، مؤثرة في قيمتها الأولى.

تمرير المحددات بالإشارة له مايبرره فيما يتعلق بالأنواع التراتبية ordinal، و الجمل strings بالطريقة التقليدية، و بالتسجيلات records الضخمة. في الواقع إن كائنات objects دلفي دائما يتم تمريرها بالقيمة، لأنها هي نفسها إشارة. لهذا السبب فإن تمرير الكائنات بإشارتها لامعنى له تقريبا (ما عدا بعض الحالات الخاصة جدا)، لأنها كما لوكانت "تمرير إشارة بالإشارة".

جمل strings دلفي الضخمة لها سلوك مختلف بعض الشيء: فهي تتصرف و كأنها إشارة، لكنك إذا قمت بتغيير واحدة من متغيرات الجمل التي تشير إلى نفس الجملة في الذاكرة، يتم نسخها قبل تحديثها. الجمل الطويلة التي تمرر كمحدد بقيمة تتصرف و كأنها إشارة فقط من حيث استخدام الذاكرة و سرعة الشغيل. لكن إذا قمت بتعديل قيمة الجملة ، فإن القيمة الأصلية لاتتأثر، بالمقابل، إذا مررت الجملة الطويلة بالإشارة، يمكنك تغيير القيمة الأصلية.

ملاحظة

أدخلت دلفي 3 نوعا جديدا من المحددات، وهي out. محدد out ليس لديه قيمة ابتدائية و يستخدم فقط لترجيع قيمة. هذه المحددات يجب استخدامها فقط لإجرائيات و وظائف COM ؛ عموما، من الأفضل التشبت بمحددات var الأكثر فعالية. محددات out تتصرف مثل محددات var بإستثناء عندما لا يوجد لديها قيمة ابتدائية.

محددات الثوابت

كبديل للمحددات بالإشارة، يمكنك استعمال محدد const. بما أنه لايمكنك تخصيص قيمة لمحدد ثابت داخل الإجرائية، يمكن للمجمع تحسين كفاءة تمرير المحدد. المجمع يمكن أن يختار أسلوبا شبيها بالمحددات بالإشارة (أو الإشارة لثابت const reference حسب مصطلحات س++)، لكن التصرف سيبقى شبيها بالمحددات بالقيمة، لأن القيمة الأصلية لن تتأثر بالإجرائيات.

في الواقع، إذا حاولت تجميع التوليف التالي، :

 

function DoubleTheValue (const Value: Integer): Integer;

begin

  Value := Value * 2;      // compiler error

  Result := Value;

end;

ستقوم دلفي باصدار خطأ , يقول

Left Side cannot be assigned to

لان قيمة value قيمة تابتة لايمكن تغييرها , وهي تشبه كتابة الجملة التالية

 

7:=8;

فلا يمكن تغيير قيمة 7 ,

و لتصحيح الخطاء في البرنامج السابق يكون بازالة كلمة const ليصبح value متغير عادي .

وشكرا

مــــMADIــــدي

#19

تابع الاجراءات و الوظائف

محددات المصفوفة المفتوحة

عكس لغة س، وظيفة أو إجراء دلفي لديهما دائما عددا ثابتا من المحددات, إلا أنه توجد طريقة لتمرير عددا غير ثابت من المحددات إلى الإجرائية بإستخدام المصفوفة المفتوحة open array.

التعريف الأساسي لمحدد مصفوفة مفتوحة open array parameter هو مصفوفة مفتوحة ذات نوع. هذا يعني انك تشير إلى نوع المحدد لكنك لاتعرف كم عنصر من هذا النوع سيكون لدى المصفوفة. هنا مثال لمثل هذا التعريف:

 

function Sum (const A: array of Integer): Integer;

var

  I: Integer;

begin

  Result := 0;

  for I := Low(A) to High(A) do

    Result := Result + A;

end;

بإستخدام High(A) يمكننا الحصول على حجم المصفوفة، لاحظ أيضا استخدام قيمة الترجيع في الوظيفة، Result، لتخزين قيم مؤقتة. يمكنك استدعاء هذه الوظيفة بأن تمرر إليها مصفوفة من التعبيرات ذات نوع صحيح Integer.

 

X := Sum ([10, Y, 27*I]);

إذا كان لديك مصفوفة من أي حجم ذات نوع صحيح، تستطيع تمريرها مباشرة لإجرائية تتطلب محدد بمصفوفة مفتوحة، أو بدلا من ذلك، يمكنك استدعاء وظيفة Slice لتمرير جزء فقط من المصفوفة (كما هو مشار اليه في ثاني محدد في الوظيفة). هنا مثال، حيث مصفوفة كاملة تم تمريرها كمحدد:

 

var

  List: array [1..10] of Integer;

  X, I: Integer;

begin

  // initialize the array

  for I := Low (List) to High (List) do

    List  := I * 2;

  // call

  X := Sum (List);

إذا أردت تمرير فقط جزء من المصفوفة إلى وظيفة Sum، ببساطة قم باستدعائها بالطريقة التالية:

 

X := Sum (Slice (List, 5));

ملاحضة :

المصفوفات المفتوحة النوعية في دلفي 4 متوافقة تماما مع المصفوفات الحية dynamic. المصفوفات الحيوية تستخدم نفس الصيغة في المصفوفات المفتوحة، مع اختلاف انه يمكنك استخدام التركيب array of Integer لتعريف متغير، و ليس فقط لتمرير محدد.

وشكرا

مــــMADIــــدي

#20

سلام الله عليكم

اخى العزيز ===> madi <===

معلومات ممتازة جدا واتمنى ان ارى باقى درسك هذا

واسمح لى ان اضيف موضوعك هذا بشريط الاخبار فوق تحت اسم

تعلم الدلفى

لك هذه منى (f) (f)

#21

الف شكر لك مشرفي العزيز , و الله الموفق للجميع .

تابع الاجراءات و الوظائف :

محددات مصفوفة مفتوحة نوع متباين

بجانب هذه المصفوفات المفتوحة النوعية، تسمح لك دلفي بتحديد مصفوفات مفتوحة نوع متباين type-variant أو بلا نوع. هذا النوع الخاص من المصفوفات لديه عدد غير محدود من القيم، و التي يمكن الاستفادة منها لتمرير المحددات.

تقنيا، بنية مصفوفة الثوابت تسمح لك بتمرير مصفوفة بعدد غير محدود من العناصر من أنواع مختلفة إلى إجرائية دفعة واحدة. مثال ذلك، هنا تعريف لوظيفة Format :

 

function Format (const Format: string;

  const Args: array of const): string;

المحدد الثاني هو مصفوفة مفتوحة، تستقبل عددا غير محدود من القيم. في الواقع، يمكنك استدعاء هذه الوظيفة بالطرق التالية:

 

N := 20;

S := 'Total:';

Label1.Caption := Format ('Total: %d', [N]);

Label2.Caption := Format ('Int: %d, Float: %f', [N, 12.4]);

Label3.Caption := Format ('%s %d', [S, N * 2]);

لاحظ أنه بإمكانك تمرير المحدد كقيمة ثابت، أو قيمة متغير، أو كتعبير. تعريف وظيفة من هذا النوع أمر سهل، لكن كيف تقوم بتوليفه؟ كيف تتعرف على نوع المحددات؟ ان قيم محددات مصفوفة مفتوحة نوع متباين هي متوافقة مع عناصر نوع TVarRec.

تسجيلة TVarRec لها البُنية التالية:

 

type

  TVarRec = record

    case Byte of

      vtInteger:    (VInteger: Integer; VType: Byte);

      vtBoolean:    (VBoolean: Boolean);

      vtChar:       (VChar: Char);

      vtExtended:   (VExtended: PExtended);

      vtString:     (VString: PShortString);

      vtPointer:    (VPointer: Pointer);

      vtPChar:      (VPChar: PChar);

      vtObject:     (VObject: TObject);

      vtClass:      (VClass: TClass);

      vtWideChar:   (VWideChar: WideChar);

      vtPWideChar:  (VPWideChar: PWideChar);

      vtAnsiString: (VAnsiString: Pointer);

      vtCurrency:   (VCurrency: PCurrency);

      vtVariant:    (VVariant: PVariant);

      vtInterface:  (VInterface: Pointer);

  end;

كل تسجيلة محتملة لديها حقل نوع VTipe ، بالرغم انه ليس سهلا رؤيته من المرة الأولى لأن تعريفه يتم مرة واحدة فقط.

بواسطة هذه المعلومات يمكننا فعلا كتابة وظيفة قادرة على التعامل مع أنواع بيانات مختفلة. في مثال وظيفة SumAll ، أريد أن أكون قادرا على جمع قيم من أنواع مختلفة، تحويل الجمل إلى أعداد صحيحة، الحروف إلى ما يقابلها من قيمة ترتيبية، و إضافة 1 للقيم البولية الموجبة. التوليف يعتمد على تعليمة case، و يعد سهلا، بالرغم من أنه علينا التعامل مع المؤشرات pointers أكثر من مرة:

 

function SumAll (const Args: array of const): Extended;

var

  I: Integer;

begin

  Result := 0;

  for I := Low(Args) to High (Args) do

    case Args .VType of

      vtInteger: Result :=

        Result + Args .VInteger;

      vtBoolean:

        if Args .VBoolean then

          Result := Result + 1;

      vtChar:

        Result := Result + Ord (Args .VChar);

      vtExtended:

        Result := Result + Args .VExtended^;

      vtString, vtAnsiString:

        Result := Result + StrToIntDef ((Args .VString^), 0);

      vtWideChar:

        Result := Result + Ord (Args .VWideChar);

      vtCurrency:

        Result := Result + Args .VCurrency^;

    end; // case

end;

و لتجريب ذلك ضع زر على الفورم و اضغط ضغط ممتالى على الزر واكتب الجمل التالية , بعد ان تضع التوليف السابق قبله .

 

procedure TForm1.Button4Click(Sender: TObject);

var

  X: Extended;

  Y: Integer;

begin

  Y := 10;

  X := SumAll ([Y * Y, 'k', True, 10.34, '99999']);

  ShowMessage (Format (

    'SumAll ([Y*Y, ''k'', True, 10.34, ''99999'']) =     >  %n', [X]));

end;

وشكرا

مــــMADIــــدي

#22

التعريف المسبق

عندما تحتاج إلى استخدام معرف identifier (من أي نوع)، يجب أن يكون المجمع قد رأى بالفعل تحديدا ما ليعلم إلى ماذا يشير هذا المعرف. لهذا السبب، فأنت عادة ما تقدم تعريفا كاملا قبل استخدام أية إجرائية. على أية حال، توجد حالات لا يمكنك فيها ذلك. إذا فرضنا أن الإجراء A يستدعي الإجراء B، و الإجراء B يستدعي الإجراء A، عندما تبدأ بكتابة التوليف، فستحتاج إلى مناداة إجرائية لا يزال المجمع لم يصل الى تعريفها.

إذا أردت تعريف إجراء أو وظيفة بإسم معين و محددات معطاة، من غير تقديم توليفها الفعلي، يمكنك كتابة الإجراء أو الوظيفة متبوعة بالكلمة المفتاحية forward:

procedure Hello; forward;

لاحقا، يجب أن يقدم التوليف تعريفا كاملا للإجراء، لكن هذا يمكن استدعاؤه حتى قبل أن يتم تعريفه بالكامل. فيما يلي مثال:

 

procedure Hello;

begin

    DoubleHello

end;







procedure DoubleHello;

begin

    ShowMessage ('Hello');

    ShowMessage ('Hello');

end;

تلاحظ أن الاجراء Hello يقوم بمناداة الاجراء DoubleHello , ولكن مكان كتابة الاجراء DoubleHello كان بعد مكان كتابة الاجراء Hello , و عند تنفيدك لهدا البرنامج سوف يعطيك المجمع رسالة خطاء عند مكان مناداة الدالة DoubleHello داخل الاجراء Hello يفيد بأن الدالة DoubleHello غير معرفة , الان احد الحلول التي يمكن اجراءها هو كتابة الاجراء DoubleHello قبل الاجراء Hello , او بامكانك استخدام التعريف المسبق , كالتالي :

 

procedure DoubleHello; forward;



procedure Hello;

begin

    DoubleHello

end;



procedure DoubleHello;

begin

    ShowMessage ('Hello');

    ShowMessage ('Hello');

end;

بالرغم من أن تعريف الإجراء المسبق forward procedure ليس شائعا في دلفي، توجد حالة مشابهة و التي تتكر أكثر. عندما تقوم بتعريف إجرائية أو وظيفة في جزء الواجهة interface في الوحدة unit ، يتم إعتباره تعريفا مسبقا، حتى إذا كان مصطلح forward غير ظاهر. فعليا لايمكنك أن تكتب جسم الاجرائية في جزء الواجهة. في نفس الوقت، يجب أن تقوم بتقديم التنفيذ الفعلي لكل إجرائية قمت بتعريفها، وذلك في نفس الوحدة( سوف نتكلم عن دللك بالتفصيل اكتر لاحقا ).

نفس الشيء ينطبق على تعريف المسار methos داخل نوع طبقة class و الذي يتم توليده آليا بواسطة دلفي (كما يحدث عند اضافة حدث لنموذج أو أحد مكوناته).

المسار methos هو نوع خاص من الوظائف أو الإجرائيات ذات علاقة بنوع بيانات، الطبقة class. في دلفي، كل مرة نتناول حدثا، نحتاج لتعريف مسار، أو بصفة عامة إجراء. على أية حال، مصطلح مسار يستخدم للإشارة إلى الوظائف و الإجراءات ذات العلاقة بالطبقة class.

سبق لنا أن رأينا بالفعل عددا من المسارات في الأمثلة الواردة فيما سبق , في ما يلي مسار فارغ أضيف آليا بواسطة دلفي للتوليف المصدري لنموذج:

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  {here goes your code}

end;

مناولات الحدث المعرفة داخل طبقة TForm هي تعريفات مسبقة: حيث سيتم تقديم التوليف في جزء التنفيذ implementaion من الوحدة. فيما يلي مقطع من توليف مصدري للمثال السابق، مع تعريف لمسار

Button1Click :

 

type

  TForm1 = class(TForm)

    ListBox1: TListBox;

    Button1: TButton;

    procedure Button1Click(Sender: TObject);

  end;

وشكرا

مــــMADIــــدي

#23

تابع الاجراءات و الوظائف

التحميل المضاف لوظيفة فكرة التحميل المضاف overloading بسيطة: يسمح لك المجمع compiler بتحديد وظيفتين أو إجرائين يحملان نفس الإسم، بشرط أن تختلف المحددات. و باختبار هذه المحددات، يمكن للمجمع استنتاج أية نسخة من الإجرائيتين تريد استدعاؤها.

راجع هذه السلسة من الوظائف المستخرجة من وحدة Math في مكتبة VCL:

 

function Min (A,B: Integer): Integer; overload;

function Min (A,B: Int64): Int64; overload;

function Min (A,B: Single): Single; overload;

function Min (A,B: Double): Double; overload;

function Min (A,B: Extended): Extended; overload;

عندما تنادي Min (10,20)، يستنتج المجمع ببساطة بأنك تقصد استدعاء الوظيفة الأولى من المجموعة، لذا فالقيمة المرتجعة ستكون رقما صحيحا.

القواعد الأساسية اثنان:

- كل نسخة من الإجرائية يجب أن تكون متبوعة بالكلمة المفتاحية overload.

- الاختلاف يجب أن يكون في عدد أو نوع المحددات، أو في كلاهما. و ليس في نوع المرتجع، الذي لا يمكن استخدامه للتفريق بين الاجرائيتين.

فيما يلي ثلاث نسخ (بحمل مضاف ) لإجراء ShowMsg .

 

procedure ShowMsg (str: string); overload;

begin

  MessageDlg (str, mtInformation, [mbOK], 0);

end;



procedure ShowMsg (FormatStr: string;

  Params: array of const); overload;

begin

  MessageDlg (Format (FormatStr, Params),

    mtInformation, [mbOK], 0);

end;



procedure ShowMsg (I: Integer; Str: string); overload;

begin

  ShowMsg (IntToStr (I) + ' ' + Str);

end;

الوظائف الثلاثة تعرض نافذة رسالة مع جملة، بعد صياغة متكررة للجملة بعدة طرق. لنرى النداءات الثلاث للبرنامج:

 

ShowMsg ('Hello');

ShowMsg ('Total = %d.', [100]);

ShowMsg (10, 'MBytes');

ما يدهش هو ان تقنية Code Parameters محددات التوليف في دلفي تعمل بصورة رائعة مع محددات الحمل المضاف. فمع بداية فتح قوس في طباعتك بعد اسم الإجرائية، يتم عرض كل البدائل المتوفرة. و مع ادخالك للمحدد، تقوم دلفي باختبار نوعه لتقرير أيا من البدائل لايزال متوفرا, يمكنك رؤية هذا بعد البدء بكتابة ثابت جملة تعرض دلفي نسخة متوافقة واحدة (تستثني نسخة إجراء ShowMsg الذي لها نوع صحيح كأول محدد).

حقيقة أن كل نسخة من إجرائية حمل مضاف overloaded يجب أن تكون معلمة بوضوح؛ هذا يعني ضمنا أنك لاتستطيع تحميل إجرائية موجودة في نفس الوحدة unit وليست معلمة بمصطلح overload. (رسالة الخطأ التي تظهر لك عندما تحاول ذلك هي: تعريف سابق ل <اسم الاجرائية> ليست معلمة بتوجيه 'overload'.) عموما ، يمكنك اجراء تحميل اضافي لإجرائية تكون قد سبق تعريفها في وحدة مختلفة. هذا لأجل التوافقية مع النسخ السابقة من دلفي، و التي تسمح لعدة وحدات أن تعيد استخدام نفس اسم الإجرائية. لاحظ، على أية حال، بأن هذه الحالة الخاصة ليست ميزة اضافية للتحميل المضاف، لكنها اشارة الى المشكلات التي قد تواجهها.

مثلا، يمكنك اضافة التوليف التالي للوحدة:

 

procedure MessageDlg (str: string); overload;

begin

  Dialogs.MessageDlg (str, mtInformation, [mbOK], 0);

end;

ملاحظة : MessageDlg هو اجراء موجود اصلا في دلفي تابعة لمكتبة VCL ,

نرجع للتوليف السابق ,هذا التوليف لا يقوم فعلا بحمل اضافي لإجرائية MessageDlg الأصلية. في الواقع إذا كتبت:

 

MessageDlg ('Hello');

سوف تتحصل على رسالة خطأ لطيفة تشير إلى غياب بعض المحددات. الطريقة الوحيدة لإستدعاء نسخة محلية بدلا من أخرى تابعة لمكتبة VCL هي في أن تشير صراحة إلى الوحدة المحلية مكان كتابة الاجراء متلا Form1، الأمر الذي يخدش فكرة التحميل المضاف:

 

Form1.MessageDlg ('Hello');

وشكرا

مــــMADIــــدي

#24

الجمل Strings

نوع الجملة يشبه نوع مصفوفة. في الواقع، ان الجملة هي تقريبا مصفوفة من أحرف. ما يبين هذا؛ حقيقة أنه يمكنك الوصول إلى حرف معين في الجملة باستخدام تركيبة [].

يوجد في الواقع ثلاث أنواع جمل:

· نوع ShortString جملة قصيرة ، هذه الجمل محدودة ب 255 حرف و تتماشى مع الجمل في نسخة 16-بت من دلفي. كل جزء من جملة قصيرة هي من نوع ANSIChar (النوع القياسي للأحرف).

· نوع ANSIString و يتطابق مع جديد الجمل الطويلة متغيرة الطول. هذه الجمل يتم تخصيصها حيويا، هي معدودة الاشارة reference counted ، و تستخدم تقنية copy-on-write نسخ عند الكتابة. حجم هذه الجمل غير محدود تقريبا (يمكنها التخزين لغاية 2 بليون حرف!). وهي أيضا مبينة على نوع ANSIChar.

· نوع WideString جملة عريضة وهي تشبه نوع ANSIString لكنها مبنية على نوع WideChar . لتخزين أحرف Unicode.

وشكرا

مــــMADIــــدي

#25

النظر إلى الجمل في الذاكرة

لمساعدتك على فهم أفضل لتفاصيل إدارة الذاكرة للجمل، قم بكتابة المثال التالي. قم بتعريف جامع global لجملتين: Str1 و Str2. وهو كالتالي ( لا حظ مكان التعريف في جزء interface )

 [l]

var

  Form1: TForm1;

  Str1,Str2:string;



implementation

[/l]

بجانب التعامل مع الجمل، يقوم البرنامج بعرض حالتها الداخلية في مربع قائمة listbox، مستعملا وظيفة StringStatus التالية ( ضعها في جزء implementation ) :

 [l]

implementation



{$R *.DFM}



function StringStatus (const Str: string): string;

begin

  Result := 'Address: ' + IntToStr (Integer (Str)) +

    ', Length: ' + IntToStr (Length (Str)) + 

    ', References: ' + IntToStr (PInteger (Integer (Str) - 8)^) +

    ', Value: ' + Str;

end;

[/l]

شرح لهده الوظيفة :

للحصول على عنوان موقع الجملة في الذاكرة (مفيد لمعرفة صفتها الفعلية و لرؤية متى تقوم جملتان بالإشارة إلى نفس منطقة الذاكرة)، تم تلبيس نوع typecast من نوع جملة إلى نوع صحيح. الجمل عمليا هي إشارات، هي مؤشّرات: قيمتها تحوي موقع الذاكرة الفعلي للجملة

من أجل إستخراج عدد الإشارات، تم جعل التوليف يعتمد على حقيقة غير معروفة عند الكثيرين و هي أن الطول و عدد الإشارات يتم تخزينها فعليا في الجملة، قبل النصّ الفعلى وقبل الموقع الذي يشير اليه متغيّر الجملة. الموقع (بالسالب) هو -4 و فيه طول الجملة (قيمة يمكنك استخراجها بسهولة أكبر باستعمال وظيفة Length) و -8 و فيه عدد الإشارات ( عدد الاشارات هو عدد المتغيرات التي تشير الى هدا الموقع من الداكرة ) .

تذكّر بأن هذه المعلومات الداخلية المتعلقة بمواقع الذاكرة offsets يمكن أن تتغيّر في النسخ المستقبلية من دلفي؛ أيضا لا يوجد أية ضمانة بأن خصائص مشابهة و غير موثّقة سيتم الاحتفاظ بها مستقبلا .

الآن لنتابع البرامج :

ضع زر و ListBox على الفورم : وفي الحدت Onclick الخاص بالزر ضع التالي :

 [l]



procedure TForm1.Button1Click(Sender: TObject);

begin 

Str1 := 'Hello';

ListBox1.Items.Add ('Str1 - ' + StringStatus (Str1));





Str2 := Str1;

ListBox1.Items.Add ('Str2 := Str1');

ListBox1.Items.Add ('Str1 - ' + StringStatus (Str1));

ListBox1.Items.Add ('Str2 - ' + StringStatus (Str2));





Str1 [2] := 'a';

ListBox1.Items.Add ('Str1 [2] := ''a''');

ListBox1.Items.Add ('Str1 - ' + StringStatus (Str1));

ListBox1.Items.Add ('Str2 - ' + StringStatus (Str2));



end;



[/l]

بتشغيل البرنامج تضهر النتائج التالية :

 [l]





Str1 - Address: 12531244, Length: 5, References: 1, Value: Hello



Str2 := Str1

Str1 - Address: 12531244, Length: 5, References: 2, Value: Hello

Str2 - Address: 12531244, Length: 5, References: 2, Value: Hello 

Str1 [2] := 'a'

Str1 - Address: 12531888, Length: 5, References: 1, Value: Hallo

Str2 - Address: 12531244, Length: 5, References: 1, Value: Hello



[/l]

التحليل :

ان ناتج الجملة

 [l]



Str1 := 'Hello';

ListBox1.Items.Add ('Str1 - ' + StringStatus (Str1

كان

Str1 - Address: 12531244, Length: 5, References: 1, Value: Hello



[/l]

حيت أن 12531244 هو عنوان هده الجملة في الداكرة , و طولها 5 , و عدد المتغيرات التي تشير اليها 1 ,

أما ناتج الجملة

Str2 := Str1;

كان

 [l]



Str2 := Str1

Str1 - Address: 12531244, Length: 5, References: 2, Value: Hello

Str2 - Address: 12531244, Length: 5, References: 2, Value: Hello





[/l]

حيت نلاحظ أن عملية التخصيص ( = ) أعطت المتغير Str2 نفس عنوان الجملة Str1

وأن عدد الاشارات اصبح 2 , لأن عدد المتغيرات التي تشير الى هده الجملة في الذاكرة هما المتغيران str1 و str2 ,

أما ناتج الجملة

 [l]

Str1 [2] := 'a';

ListBox1.Items.Add ('Str1 [2] := ''a''');

ListBox1.Items.Add ('Str1 - ' + StringStatus (Str1));

ListBox1.Items.Add ('Str2 - ' + StringStatus (Str2));

[/l]

فكان

 [l]

Str1 [2] := 'a'

Str1 - Address: 12531888, Length: 5, References: 1, Value: Hallo

Str2 - Address: 12531244, Length: 5, References: 1, Value: Hello

[/l]

مادا تلاحظ من تغير لعنوان كل جملة أيضا تغير عدد الإشارات ,

حجم الجمل و الداكرة

شي أخر مهم إذا أردت زيادة حجم جملة في الذاكرة لكن المنطقة المجاورة من الذاكرة تكون محجوزة من قبل شيء آخر، عندها لا يمكن للجملة أن تتوسع في نفس منطقة الذاكرة، بل يجب أخذ نسخة كاملة من الجملة و نقلها لمكان آخر في الذاكرة. قم بتحديد السعة القصوى للجملة بواسطة إجراء SetLength، و سيتم تخصيص المقدار المطلوب من الذاكرة بكفاءة.

 [l]

SetLength (String1, 200);

[/l]

إجراء SetLength يقوم بطلب ذاكرة، و ليس بعملية تخصيص فعلية لذاكرة. أنه يحتفظ يمساحة الذاكرة المطلوية لإستعمالها لاحقا، بدون أن يقوم باستعمالها فعليا. هذه التقنية تعتمد على خاصية في أنظمة تشغيل ويندوز، و تستخدمها دلفي لجميع تخصيصات الذاكرة الحيوية. مثلا عندما أنت تقوم بطلب مصفوفة ضخمة جدا، يتم الحجز في الذاكرة المطلوبة و لكن لا يتم تخصيصها.

نادرا ما تدعو الحاجة إلى تحديد طول لجملة. الحالة الوحيدة التي يجب فيها أن تقوم بتخصيص ذاكرة لجملة طويلة باستخدام SetLenth هي عندما يتطلب الأمر منك تمرير جملة كمحدد الى وظيفة API (بعد تلبيس نوع مناسب) .

و شكرا

[gl]مــــMADIــــدي[/gl]

هذا الموضوع مغلق.

مواضيع مشابهة