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

حفظ الشجرة إلى ملف

بدأه booknet في 10 مارس 2008 · 1 رد · 640 مشاهدة · في Microsoft Visual Basic.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

أرجو مساعدتكم في كيفية حفظ الشجرة (treeview) إلى ملف

وشكرا

#2
اقتباس
حفظ عناصر الشجرة في ملفّ:

تتوقّع أنّي سأقول لك إنّ الأمر في غاية البساطة، فكلّ ما عليك هو استخدام عمليّة السلسلة Serialization التي شرحناها في فصل "التعامل مع المفّات والمجلّدات"، وبذلك يمكنك حفظ الشجرة وكلّ محتوياتها في ملفّ بجملة واحدة!

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

إذن ما العمل؟

يمكننا ببعض التحايل، أن نخزّن كلّ محتويات الشجرة في أيّ مجموعة قابلة للسلسلة (مثل المصفوفة القائمة ArrayList)، ثمّ بعد ذلك نحفظ هذه المجموعة في ملفّ!

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

من أجل هذا سنعرّف سجلا قابلا للسلسلة Serializable، بحيث يحتوى على خاصيّتين: نصّ العنصر ومستواه في الشجرة:

<Serializable()> Structure sNode

Dim node As String

Dim level As Integer

End Structure

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

وبالنسبة لمستوى العنصر، فسيكون صفرا إذا كان العنصر أحد جذور الشجرة، و 1 إذا كان العنصر أحد العناصر المتفرّعة من جذر الشجرة، و 2 إذا كان العنصر متفرّعا من عنصر مستواه = 1، وهكذا... مستوى كلّ عنصر يزيد عن مستوى الفرع الذي يحتويه بواحد.

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

والآن سنكتب كود حفظ الشجرة.. إنّ كلّ ما سنفعله، هو كتابة إجراء اسمه SaveTree لإضافة نصّ العنصر المرسل إليه ومستواه في سجل من النوع sNode، وإضافة هذا السجلّ إلى المصفوفة القائمة TreeList، التي سنعرّفها على مستوى النموذج كالتالي:

Dim TreeList As New ArrayList()

ها هو ذا كود الإجراء SaveTree:

Sub SaveTree(ByVal node As TreeNode)

Dim myNode As sNode

myNode.level = node.FullPath.Split("\"c).GetUpperBound(0)

myNode.node = node.Text

TreeList.Add(myNode)

End Sub

هل أدركت ما يفعله السطر الثاني في الإجراء السابق؟

إنّه يستخدم خاصيّة المسار الكامل للعنصر FullPath ليستنتج منها مستواه، وذلك بتقطيع هذا المسار إلى عناصره.. هذه العناصر تفصل بينها في المسار العلامة "\".. إنّ العناصر الناتجة ستوضع في المصفوفة التي تعيدها الدالة Split.. رقم الخانة الأخيرة في هذه المصفوفة هو مستوى العنصر (لأنّه أقلّ من عدد الخانات بواحد).

الآن كلّ ما علينا فعله هو استدعاء الإجراء ScanNode ـ الذي كتبناه من قبل ـ وإرسال الإجراء SaveTree كمعامل له، بحيث توضع كلّ عناصر الشجرة في المصفوفة القائمة:

Dim RootNode As TreeNode

For Each RootNode In TreeView1.Nodes

ScanNode(RootNode, AddressOf SaveTree)

Next

والآن لم يتبقّ إلا حفظ المصفوفة القائمة بالطريقة التي تعلّمناها من قبل.. افترض أنّ FileName هو متغيّر يحتوى على اسم ومسار الملفّ الذي اختاره المستخدم بواسطة مربّع حوار "حفظ ملفّ".. هذا هو الكود الذي يحفظ المصفوفة القائمة:

Dim formatter As New BinaryFormatter

Dim saveFile As FileStream

saveFile = File.Create(FileName)

formatter.Serialize(saveFile, TreeList)

saveFile.Close()

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

Dim formatter As New BinaryFormatter

Dim openFile As FileStream

openFile = File.Open(FileName, FileMode.Open)

TreeList = CType(formatter.Deserialize(openFile), ArrayList)

openFile.Close()

لم يبقَ إلا إعادة العناصر إلى أفرعها على الشجرة.. هذا هو الكود الذي يقوم بهذا:

Dim o As sNode

Dim currNode As TreeNode

Dim CurrLevel As Integer = 0

Dim i As Integer

For i = 0 To TreeList.Count - 1

o = CType(TreeList(i), sNode)

If o.level = CurrLevel Then

If CurrLevel = 0 Then

' هذا العنصر من جذور الشجرة

currNode = TreeView1.Nodes.Add(o.node)

Else ' العنصران في مستوى واحد،

' أضف العنصر الجديد لنفس فرع العنصر الحالي

' العنصر الذي سنضيفه سيصبح هو العنصر الحالي

currNode = currNode.Parent.Nodes.Add(o.node)

End If

ElseIf o.level > CurrLevel Then

' مستوى العنصر الجديد أكبر من مستوى العنصر الحالي

' إذن فالعنصر الجديد متفرّع من العنصر الحالي

' وسيصبح العنصر الجديد بعد إضافته هو العنصر الحالي

currNode = currNode.Nodes.Add(o.node)

' لا تنس أن تزيد مستوى العنصر الحالي بواحد

CurrLevel = o.level

Else ' إذا كان مستوى العنصر الجديد أصغر من المستوى الحالي

' فيجب أن ننقص المستوى الحالي بمقدار الفرق بينَهما

' إلى أن نصل للفرع الذي سنضع فيه العنصر الجديد

While o.level <= CurrLevel

currNode = currNode.Parent

CurrLevel -= 1

End While

' أضف العنصر الجديد للفرع الذي وصلنا إليه،

' واجعل العنصر الجديد هو العنصر الحالي

currNode = currNode.Nodes.Add(o.node.ToString)

' لا تنس أن تزيد مستوى العنصر الحالي بواحد

CurrLevel = o.level

End If

Next

ويحتوى النموذج الرئيسيّ في المشروع Globale في مجلّد برامج هذا الفصل على القائمة File، التي تمنحك الأمران Save و Load، وهما يقومان بالوظيفتين اللتين شرحناهما توّا.. الجدير بالذكر أنّ هذا التطبيق قد وضع دالتي الحفظ والتحميل في خليّة Class، حتّى يمكنك استخدام هذه الخليّة بسهولة من أيّ مشروع آخر.

منتقول من كتاب ... احتراف Visual Basic .Net لمحمد حمدي غانم

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