Shagrouni

كيف تسرع عمليات القوائم

خالد الشقروني, 23 سبتمبر 2000

الأمرين BeginUpdate-EndUpdate يسهمان بشكل كبير في تسريع عمليات الاضافة والالغاء لعناصر القوائم في كثير من المكونات. هذه المقالة تلقي الضوء على ذلك مع بعض الأمثلة.

قد نرهق اصدقاءنا دون أن ندري، قليل من التفهم يعني الكثير.

أوراق دلفي

لا أعلم لماذا ينسى الكثيرون (أنا من بينهم) الخدعة القديمة المتمثلة في الأمرين: BeginUpdate-EndUpdate . وذلك عند التعامل مع عناصر في قائمة .

سأوضح أكثر. كثيرا ما نحتاج في برامجنا الى التعامل مع مكونات مثل ListBox، TMemo، TTreeView. هذه المكونات و غيرها تملك سمات properties تمثل عناصرها مثل : Items في TListBox، والتي تمثل عناصر القائمة ، و Lines و تمثل الأسطر في TMemo، أو أغصان الشجرة Items في TreeView.

لنأخذ المثال التالي:

procedure TForm1.Button1Click(Sender: TObject);
var
 i: integer;
 Node: TTreeNode;
begin
  for i := 1 to 100 do
    begin
      Node := Treeview1.Items.Add(nil, IntToStr(i));
      Treeview1.Items.AddChild(Node, 'Child Node');
    end;
end;
      

المثال السابق يقوم باضافة 100 عنصر في مكون TTreeView، وتحت كل عنصر يضيف عنصرا تابعا له، هذا يعنى ما مجموعه 200 عنصر. (لتنفيذ المثال قم بوضع TreeView1 في Form1 و زرا Button1. في حدث onClick الخاص بالزر ضع اسطر المثال السابق في المكان المناسب.)

قم بتنفيذ البرنامج و اضغط على الزر لمباشرة عمليات اضافة الأغصان (Items) الى الشجرة. ستلاحظ البطء العجيب الذي تتم فيه هذه العملية. (سيكون الأمر كارثة حقا لو حاولت اضافة 1000 عنصر بدلا من 100! )

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

نفس هذا الأمر يتكرر مع مكونات أخرى مثل TMemo:

Memo1.Lines.Add (IntToStr(i));

أو مع TlistBox:

ListBox1.Items.Add (IntToStr(i));

ولكننا اخترنا TreeView كمثال لأن البطء فيه ملحوظ أكثر.

عودة الى الخدعة

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

فيما يلي نفس المثال السابق بعد أن تم تعديله بإضافة هذين الأمرين:

procedure TForm1.Button1Click(Sender: TObject);
var
 i: integer;
 Node: TTreeNode;
begin
  Treeview1.Items.BeginUpdate; // 1
  
  for i := 1 to 1000 do
    begin
      Node := Treeview1.Items.Add(nil, IntToStr(i));
      Treeview1.Items.AddChild(Node, 'Child Node');
    end;

  Treeview1.Items.EndUpdate;  // 2
  
end;
      

لاحظ اننا زدنا عدد التكرارات من 100 إلى 1000 هذا يعني اضافة ما مجموعه 2000 عنصر. قم بتشغيل المثال الآن و لاحظ الفرق - الكبير جدا-. 

نفس الشيء يمكن استخدامه عند تصفية العناصر أو الغاء بعضها، كما هو موضح في المثال التالي:

procedure TForm1.Button2Click(Sender: TObject);
begin
  Treeview1.Items.BeginUpdate;
  Treeview1.Items.Clear;
  Treeview1.Items.EndUpdate;
end;
      

الأمرين BeginUpdate-EndUpdate يمكن استعمالهما مع العديد من المكونات الأخرى، مع كل ما كان نوعه TStrings مثل: TListBox.Items، TCombox، TMemo.Lines، TRichEdit.Lines، وغيرها كثير. أيضا مع TListView.Items، TTreeView.Items، .. (انظر المساعدة في دلفي).

هذا كل شيء. حظا موفّقا.

 

 

Shagrouni 2001 Khaled Shagrouni  khaled@shagrouni.com