المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : الدرس الثامن : المصفوفات والقوائم - دورة CSharp 2005


khaledbelal
03-22-2010, 03:47 PM
الدرس الثامن
المصفوفات:

المصفوفات هي عبارة عن مجموعة متغيرات من نفس النوع متراصة ومترابطة داخل كائن Array
ويتم الوصول لأي عنصر في هذه المجموعة من خلال ترتيبة في المجموعة Index
مثلاً : مصفوفة أيام الأسبوع تعتبر مجموعة متغيرات من نوع نص
و مصفوفة أيام الشهر تعتبر مجموعة متغيرات من نوع رقم ..
يتم تعريف المصفوفة بإحدى ثلاث طرق :

1-طريقة تعريف إسم المصفوفة فقط

التعريف بهذه الطريقة نادراً ما يستخدم , ويحدد فقط إسم لكائن المصفوفة بدون أن يقوم بإنشاءة:

string[] days;

الكود السابق يعرف إسم days لمصفوفة عناصرها من نوع نص
لاحظ القوسين المربعين بعد كلة string دلالة على أن days تمثل مصفوفة نصوص وليس نص
2-طريقة تعريف المصفوفة وتحديد عدد عناصرها
طريقة التعريف هذه تعرف و تنشئ كائن مصفوفة وتحدد عدد عناصر هذه المصفوفة:

string[] days= new string[7];

لأن المصفوفة هي كائن وجب علينا تعريفه بإستخدام عبارة new
والرقم 7 بين قوسي تعريف الكائن هو عدد عناصر المصفوفة
أي أن الكود السابق عرف مصفوفة إسمها days تحتوي على 7 عناصر من نوع نص
لكن هذه الطريقة لا تحمل قيم لعناصرها , أي أنها تحتوي على 7 نصوص فارغة
3-طريقة تعريف المصفوفة وتحميل قيم لعناصرها
هذه الطريقة تعرف وتنشئ كائن المصفوفة وتحمل قيم لجميع عناصر المصفوفة:

string[] days= new string[]{"السبت","الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة"};

في الكود السابق قمنا بتعريف كائن المصفوفة وقمنا بتحميل القيم لجميع عناصره
بإدخالها كمجموعة نصوص بين حاصرتين تفصل بين كل نص وآخر علامة ,
لاحظ أنا لم نحدد عدد عناصر المصفوفة حيث سيقوم المعالج بتحديدها آلياً من خلال عد النصوص المدخلة بين الحاصرتين
ملاحظة : العناصر المدخلة بين حاصرتين يجب أن تكون من نفس نوع عناصر المصفوفة

الوصول إلى عناصر المصفوفة:
كما قلنا سابقاً يتم الوصول إلى عناصر المصفوفة من خلال ترتيب العنصر المراد الوصول إليه
والترتيب في المصفوفات يبدأ من الصفر , أي أن أول عنصر في المصفوفة ترتيبة صفر
فمثلاً في مصفوفة الأيام , يوم السبت ترتيبة صفر و الأحد ترتيبة 1 ... والجمعة ترتيبة 6
ويتم الوصول إلى العنصر المحدد بكتابة إسم المصفوفة الموجود بها متبوعا بقوسين مربعين بينهما ترتيب العنصر
ماذا لو أردنا إظهار رسالة تخبرنا بالعنصر الذي ترتيبة 4 في مصفوفة الأيام :

string[] days= new string[]{"السبت","الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة"};
MessageBox.Show(days[4]);

لاحظ كيف تم الوصول إلى العنصر الرابع في مصفوفة days من خلال العبارة days[4]
الكود السابق ينتج هذه الرسالة :

http://absba7.absba.org/teamwork8/455943/62.jpg

يمكن أيضاً تعديل أي عنصر من عناصر المصفوفة من خلال ترتيبة في المصفوفة :

string[] days= new string[]{"السبت","الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة"};
days[4]="الأربعاء بعد التعديل";
MessageBox.Show(days[4]);

في السطر الثاني غيرنا قيمة العنصر الذي ترتيبة 4 إلى "الأربعاء بعد التعديل"
الكود السابق ينتج الرسالة التالية :

http://absba7.absba.org/teamwork8/455943/63.jpg

القوائم
مع أن المصفوفات تعتبر من أهم هياكل البيانات التي استخدمت في لغات البرمجه منذ نشأتها
إلا أن لها عدداً من العيوب التي سعت C#2005 لحلها من خلال إدخال نوع جديد من هياكل البيانات
اهم العيوب هو حجم المصفوفة الثابت , فعند تعريف مصفوفة وإسناد قيم لها أو تعريف حجمها
لن تستطيع أن تزيد من حجمها أو تنقص منه , وأيضاً لا توجد طريقة فعالة للبحث بين العناصر
مثلاً في مصفوفة أيام الأسبوع لا يوجد طريقة للبحث عن يوم السبت مثلاً إلى باستخدام دوارة تمر بجميع عناصر المصفوفة:

for(int i=0;i<days.Lehgth;i++)
{
if (days[i]=="السبت")
{
MessageBox.Show("هذا يوم السبت");
}
}

هيكل البيانات الجديد الذي تفادى عيوب المصفوفات هو القائمة
حيث يتم تعريف القائمة وتعريف أنواع عناصرها هكذا:

List<string> dayslist;

ولأن القائمة كائن وليست متغير , فيجب إستخدام عبارة new ليصبح التعريف الصحيح هكذا:

List<string> dayslist=new List<string>();

لاحظ أننا لم نحدد لها حجم أو عدد لعناصر لأن حجمها متغير , حيث تستطيع أن تضيف لها عنصر هذا:

dayslist.Add("السبت");

كما أنك تستطيع أن تضيف لها عناصر مصفوفة كاملة:

dayslist.AddRange(days);

الكود السابق يضيف عناصر المصفوفة days إلى القائمة dayslist
وتستطيع أن تحذف منها عنصر هكذا :

dayslist[5].Remove();

الكود السابق يحذف العنصر الذي ترتيبة 5 من القائمة
كما أنك تستطيع البحث عن عنصر ما هكذا :

dayslist.Contains("السبت");

الدالة السابقة سترجع القيمة true إذا كان العنصر موجود في القائمة
أو ترجع القيمة false إذا لم يوجد العنصر في القائمة
مما سبق نستنتج أن القائمة أفضل بكثير وأسهل في الإستخدام من المصفوفة
وهذا ما سنستخدمه في تطبيقنا

التطبيق:
تشغيل أكثر من ملف
سنضيف خاصية جديدة للبرنامج وهي فتح أكثر من ملف وإضافتها إلى قائمة التشغيل
حيث سنستخدم قائمة عناصرها من نوع نص لتخزين مسارات الملفات في قائمة التشغيل
إفتح تطبيق الدرس السابق , ومن صندوق الأدوات قم بسحب أداة القائمة :

http://absba7.absba.org/teamwork8/455943/64.jpg

من خلال الخاصية (Name) في جدول الخصائص قم بتغيير إسم القائمة من ListBox1 إلى pl
ليسهل التعامل معها من الشفرة , هذه هي قائمة التشغيل
قم بإعادة ترتيب الأدوات في النافذة حتى يصبح شكلها هكذا :

http://absba7.absba.org/teamwork8/455943/65.jpg

قم بتحديد إداة OF في الشريط الأصفر تحت النافذة:

http://absba7.absba.org/teamwork8/455943/66.jpg

وإذهب إلى جدول الخصائص وقم بتغيير خاصية Multiselect إلى True

http://absba7.absba.org/teamwork8/455943/67.jpg

عند إسناد قيمة True إلى هذه الخاصية فإنها تسمح لأداة إختيار الملفات بإختيار أكثر من ملف واحد كل مرة:

http://absba7.absba.org/teamwork8/455943/68.jpg

الآن سنعرف متغير عام من نوع قائمة عناصرها نصوص لخزن مسارات الملفات المختارة بأداة إختيار الملفات
كائن القائمة موجود في فضاء الأسماء System.Collections.Generic لذلك يجب إضافة عبارة using لتضمين كائنات ودوال الفضاء
إذهب إلى شفرة النافذة وأضف عبارة using التالية تحت عبارات using الموجوده في رأس الصفحة :

using System.Collections.Generic;

إذهب إلى شفرة البرنامج وقم بكتابة الكود التالي تحت كود تعريف كائنات Audio و Vedio و type :


public List<string> albume=new List<string>();

http://absba7.absba.org/teamwork8/455943/69.jpg

تحميل قيم القائمة
أداة إختيار الملفات OF تحتوي على خاصية إستخدمناها في الدروس السابقة
وهي خاصية FileName , وهذه الخاصية تحمل قيمة من نوع نص للملف الذي قام المستخدم بإختياره
لكن ماذا لو إختيار المستخدم أكثر من ملف واحد ؟
لحسن الحظ يوجد خاصية أخرى إسمها FileNames "بزيادة حرف s عن الخاصية الأخرى"
والخاصية FileNames تحمل مصفوفة جميع الملفات الذي قام المستخدم بإختيارها
وعناصر المصفوفة من نوع نص لخزن مسارات الملفات المختارة
فمثلاً لو إختار المستخدم 3 ملفات سيكون عدد عناصر هذه المصفوفة 3
إذهب إلى التصميم وإضغط مزدوجاً على زر فتح ملف ستجد الكود التالي :

OF.ShowDialog();
LoadFile(OF.FileName);
SetTrackBar();
PlayFile();

وغيره إلى الكود إلى التالي :

OF.ShowDialog();
albume.AddRange(OF.FileNames);
LoadFile(albume[0]);
FillList();
SetTrackBar();
PlayFile();

في السطر الثاني قمنا بتحميل جميع عناصر المصفوفة OF.FileNames إلى القائمة albume
والمصفوفة OF.FileNames كما شرحنا سابقاً تحتوي على عناصر تحمل مسارات الملفات المختارة
وقمنا بإضافة عناصرها إلى القائمة albume والتي سنستخدمها في أنحاء البرنامج
في السطر الثالث قمنا بتحميل العنصر الذي ترتيبة صفر من قائمة albume حتى يتم تشغيله
وفي السطر الرابع إستدعينا إجراء FillList الذي يقوم بملئ قائمة التشغيل بأسماء الملفات في عناصر القائمة albume كما سنشرح في الفقرة التالية

إجراء FillList
هذا الإجراء سيقوم بنقل جميع عناصر القائمة albume إلى قائمة التشغيل
حتى يسهل الوصول للمقطع الصوتي المراد تشغيلة ,
لكن , القائمة albume تحتوي على مسارات الملفات كاملة , وقائمة التشغيل لا تتسع لكتابة مسار الملف كاملاً
نريد فقط أسماء الملفات في قائمة التشغيل
لحسن الحظ يوجد كائن في إطار العمل داخل الفضاء System.IO يقوم بهذا العمل
الكائن Path يحتوي على دالة GetFileName تقوم بأخذ مسار الملف كاملاً وتنتج لنا إسم الملف فقط
إذا كان مسار الملف هو

c:\sounds\s1\track.mp3

فالدالة GetFileName تأخذ المسار كامل وترجع القيمة التالية :

track.mp3

يتم إستدعاء الكائن Path من خلال كتابة عنوناه الكامل :

string FileName;
FileName=System.IO.Path.GetFileName("c://sounds//s1//track.mp3");
MessageBox.Show(FileName);

في السطر الأول عرفنا متغير من نوع نص ليحمل نتيجة الدالة GetFileName
في السطر الثاني قمنا بإستدعاء الدالة GetFileName من خلال كتابة عنوانها كاملاً
وأسندنا ناتج الدالة للمتغير FileName
السطر الثالث سينتج رسالة مكتوب عليها :
track.mp3
بعد أن شرحنا عمل الدالة GetFileName سنحتاج في هذا الإجراء أيضاً لدوارة تقوم بالمرور على كافة عناصر القائمة albume
يمكنك الرجوع للدرس الثالث ومراجعة الدوارات
تبدأ الدوارة من 0 إلى عدد عناصر القائمة , حيث يمكن معرفة عدد عناصر القائمة من خلال الخاصية Count :

albume.Count;

إفتح شفرة البرنامج , وأنسخ الكود التالي وتأكد أن يكون خارج أي إجراء آخر :

void FillList()
{
pl.Items.Clear();
for(int i=0;i<albume.Count;i++)
{
string FileName;
FileName=System.IO.Path.GetFileName(albume[i]);
pl.Items.Add(FileName);
}
}

الأمر pl.Items.Clear يقوم بتنظيف القائمة من أي عناصر موجوده مسبقاً حتى تستعد لإدخال العناصر الجديدة
الكود داخل حاصرتي for سيتم تنفيذه بعدد عناصر القائمة albume
في السطر الأول من الكود داخل حاصرتي for , قمنا بتعريف الكائن الذي سيحمل نتيجة الدالة GetFileName
وفي السطر الثاني إستدعينا الدالة GetFileName ومررنا لها العنصر الذي ترتيبة i من قائمة albume
طبعاً في أول مرة يتم تنفيذ الكود سيكون i يساوي صفر , والمرة الثانية 1 والثالثة 2
وهكذا فإن قيمة i متغيرة من مرة لأخرى
في السطر الثالث أضفنا إسم المكلف الناتج إلى قائمة التشغيل pl
..
عند تشغيل البرنامج حالياً وإختيار عدة ملفات ستنتقل جميع أسماء الملفات إلى قائمة التشغيل
ويبدأ البرنامج بتشغيل أول ملف في القائمة :

http://absba7.absba.org/teamwork8/455943/70.jpg

إختيار الملف من قائمة التشغيل
إذهب إلى التصميم , وأنقر مزدوجاً على قائمة التشغيل , ستنتقل إلى شفرة البرنامج
أنسخ الكود التالي حيث مؤشر الفارة " بين حاصرتي إجراء plSelectedIndexChanged

StopFile();
LoadFile(albume[pl.SelectedIndex]);
SetTrackBar();
PlayFile();

حيث يتم تنفيذ الكود السابق كل مرة تقوم بها بإختيار عنصر من قائمة التشغيل.
عند إختيار عنصر من قائمة التشغيل , فإن السطر الأول يقوم بإيقاف تشغيل الملف الحالي
والسطر الثاني يأخذ ترتيب العنصر المختار من قائمة التشغيل من خلال الخاصيةSelectedIndex
ويقوم بتحميل الملف من قائمة albume الذي ترتيبة هو نفس ترتيب العنصر المختار في قائمة التشغيل
السطر الثالث والرابع تم شرحهما سابقاً ..
الآن قم بتشغيل البرنامج وإختر أكثر من ملف , سيتم نقل إسماء الملفات لقائمة التشغيل
ثم تشغيل أول ملف في القائمة , وعند إختيار ملف آخر من قائمة التشغيل سيتوقف تشغيل الملف الحالي
ويبدأ تشغيل الملف المختار

خطأ شائع:
أحيانا يقم المؤقت بتغيير قيمة شريك التنقل قبل أن يتم تحميل الملف
وهذا يسبب خطأ لأن قيم شريط التنقل الكبرى والصغرى لم يتم ضبتها بعد
ولا يجوز تغيير قيمة شريك التنقل قبل ضبط قيمه الصغرى والكبرى
لمعالجة الخطأ إذهب إلى شفرة إجراء المؤقت Timer1Tick :

void Timer1Tick(object sender, System.EventArgs e)
{
if (type=="V")
{
trackBar1.Value=Convert.ToInt32(vp.CurrentPosition );
}
else if (type=="A")
{
trackBar1.Value= Convert.ToInt32(ap.CurrentPosition);
}
else if (type=="R")
{
trackBar1.Value=Convert.ToInt32(rp.GetPosition());
}
}

وأضف إلى بدايتها الكود التالي:

if (trackBar1.Maximum == 0)
{
SetTrackBar();
}

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

void Timer1Tick(object sender, System.EventArgs e)
{
try
{
if (trackBar1.Maximum == 0)
{
SetTrackBar();
}
if (type=="V")
{
trackBar1.Value=Convert.ToInt32(vp.CurrentPosition );
}
else if (type=="A")
{
trackBar1.Value= Convert.ToInt32(ap.CurrentPosition);
}
else if (type=="R")
{
trackBar1.Value=Convert.ToInt32(rp.GetPosition());
}
}
catch
{
}
}

الواجب
أرسل التطبيق.
.نهاية الدرس الثامن.
..