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

كيفية توزيع العمل في Process ؟

مغلق
بدأه آل عيد في 19 أغسطس 2001 · 6 رد · 2,134 مشاهدة · في المواضيع و الدروس القيّمة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

السلام عليكم

الأخوة الأعزاء ، كيف أستطيع أن أجعل البرنامج يستجيب للأحداث أثناء اداء عملية تأخذ وقت طويل ، لترك المجال له لإلغائها ، أي مثل DoEvents في الفيجول بيسك ؟

#2

السلام عليكم ،،

أخ عيد تنمثل عملية Doevent عملية القيام بشي ما و أثناء حدوث شي انت تحدده يتوقف عمل الاجراء الذي بين بلوك Do event ... هذا في الفيجوال بيسك ... و ليس لدينا في الفيجوال سي++ جملة Do event ، لكن في الحقيقة جملة Do event تقوم بعمل الشي نفسه اللي نقوم به في فيجوال سي ++ بشكل التالي :

1- الاجراءت اللي تبي تنفذها تحطها داخل بلوك تكرار ( أي جملة تكرار تعجبك ).

2- في داخل التكرار نقوم بعملية تشييك على طابور الرسائل ... نشوف هل يوجد هناك رسالة .. عن طريق التابع :

 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);

هذا التابع يتطلب من تعريف متغير من نوع MSG علشان ترسله وهو اللي راح يحمل قيمة الرسالة اللي راح تعالج .... بهاذي الطريقة راح تتلقى الاحدث و راح تنفذ معالجاتها بالطريقة هاذي راح تستطيع تنفيذ اللي تبيه ... سواء كنت تبي تحط زر يغير قيمة falg تشيك عليه في اللوب علشان تعرف متى تتوقف .... او شي من هذا القبيل ،،،

بأكتب برنامج يوضح الشي هذا اليوم و باحطه لك ،، انتظرني ،

تقبل تحياتي ،،،،،،،،

#3

السلام عليكم.

أخي neoo توجد طريقة أفضل لعمل هذه الطريقة و هي بانشاء Thread جديد في البرنامج يقوم بتنفيذ العملية الطويلة التي تريدها و طبعا عند إنشاء هذا ال Thread فإن الحدث الذي أنشأ ال Thread سيتكون من مجموعة بسيطة من الأوامر و يعود التحكم للبرنامج.

و إذا كنتم تريدون مثال عن ذلك فأبلغوني بذلك:)

مع التحيات.

#4

السلام عليكم،

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

من أجل كل نافذة تصلها رسائل من الوندوز يجب أن يكون لها Window Procedure أو روتين عادة مايسنى ب WndProc داخل هذا الروتين يوجد الكود الخاص بتنفيذ الرسائل الواردة . الذي ينقل الرسائل إلى هذا الروتين هو التابع DispatchMessage ..

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

بالنسبة للطريقة الأولى :

التابعان الذان يحضران الرسائل من رتل الرسائل هم PeekMessage و GetMessage . الفرق بينهما أن GetMessage تنتظر حتى تكون هناك رسالة في الرتل أما PeekMessage فلا تنظر وتعيد FALSE إذا لم يكن هناك أي رسائل واردة . أيضا GetMessage تزيل الرسالة من الرتل أما PeekMessage فيمكن أن تتحكم بازالة الرسالة أو لا عن طريق البارامتر الأخير.

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

MSG msg;
while (GetContinue())
{
	if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	// Your original code goes here
	.
	.
	.	
	.
}

لاحظ تم استخدام PM_REMOVE لأننا نريد ازالة الرسالة . وهذا ضروري لأنه إذا لم نزلها فسوف تتنفذ إلى اللانهاية .

التابع TranslateMessage وظيفته تحويل الرسائل WM_KEYDOWN و WM_KEYUP إلى WM_CHAR . و التابع DispatchMessage تم شرحه سابقا على أنه الذي ينقل الرسالة إلى ال WndProc .

أما إذا أردت أن تقوم بتنفيذ رسائل معينة فقط مثل WM_LBUTTONDOWN و WM_NCLBUTTONDOWN و WM_CLOSE فيجب أن تتأكد من الرسالة أولا قبل ازالتها من الرتل . وإليك هذا المقطع من الكود:

MSG msg;
while (GetContinue())
{
	if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
	{
		switch (msg.message) {
		case WM_LBUTTONDOWN:
		case WM_NCLBUTTONDOWN:
		case WM_CLOSE:
		   // Use PeekMessage or GetMessage
		   PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
		   TranslateMessage(&msg);
		   DispatchMessage(&msg);
		default:
		}
	}

	// Your original code goes here
	.
	.
	.	
	.
}

الأفضل طبعا استخدام ال Thread في أداء المهام ولكن يجب الحرص عند استخدام ال Thread في موضوع التواقت .

أنا كنت كاتب برنامج في موضوع تجميد أي برنامج في هذا المنتدى وهو يستخدم الثريد وهو موجود في الوصلة:

http://arabteam.nicmatic.com/atassi/TestProgThread.zip

ونفس البرنامج قمت بتعديله من أجل استخدام ال Message Bump .. وهو في الوصلة:

http://arabteam.nicmatic.com/atassi/TestProgPump.zip

image2.gif

ولكن لاحظ ماذا يحدث عند تحريك النافذة بعد الضغط على Start لكلا البرنامجين ؟؟؟ وأنت قلي أيش صار وليش صار هيك ؟

Coding on the Cloud and for the Cloud!

My Blog

#5

السلام عليكم

أخي وأستاذي هاني، هذه إجابتي على السؤال :

" إن السبب يعود في Thread ، ففي البرنامج الأول تم إنشاء ثريد آخر ، لذلك عند تحريك النافذة يقوم الويندوز بتجميد الثريد للنافذة ، ولأن الثريد للرسم منفصل فيستمر الرسم ، أما بالنسبة للبرنامج الثاني فلأن الثريد واحد يتوقف الرسم بسبب تجميد الثريد " كم درجة حصلت على إجابتي ؟ :)

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

لكن بالنسبة للطريقة PeekMessage ، لماذا أضفت يا اخ هاني هذا السطر في الشفرة الثانية :

TranslateMessage(&msg);

رغم أن الوظيفة TranslateMessage حسب ما فهمت من كلامك وظيفتها فقط تحويل رسائل الكيبورد إلى WS_CHAR ؟

و إذا أردت ان أخصص الرسائل المفحوصة للنافذة الحالية فقط كيف أحصل على الهاندل حقها ؟

وشكرا جزيلا لكم ،

[تم تعديل الرسالة بواسطة آل عيد]

#6

بصراحة أخي آل عيد .. نجحت شحط يعني على الحافة 49 من 100 .. وعطيناك علامة من عنا +1 حتى تصير 50 وتنجح .. icon10.gif .. لا تصدق عمأمزح !!

الاجابة الصحيحة هي:

البرنامج الأول : النافذة في ثريد وروتين الرسم في ثريد آخر وبالتالي روتين الرسم لا يؤثر على عملية معالجة الرسائل في ثريد النافذة ومن أحد هذه الرسائل WM_WINDOWPOSCHANGING التي تحرك النافذة . وبالتالي لا يتأثر الرسم عند تحريك النافذة .

البرنامج الثاني : ثريد النافذة وروتين الرسم في نفس الثريد . وقمنا في روتين الرسم بتفيذ الرسائل وعند بدأ تحريك النافذة يتوقف الرسم لأنه التنفيذ أصبح في روتين تحريك النافذة وذلك فورا بعد نقل الرسالة إلى ال Window Procedure في استدعاء DispatchMessage ويبقى الرسم متوقف حتى نتوقف عن تحريك النافذة فيعود التنفيذ من جديد إلى روين الرسم ..

أخي إن الذي يقوم بالتحويل هو TranslateMessage وليس DispatchMessage .. وطبعا إذا أنت لاتريد معالجة رسائل WM_CHAR في برنامجك فيمكنك الغاء استدعاء ال TranslateMessage ..

طبعا نحن مررنا NULL إلى أول بارامتر في PeekMEssage وذلك لأننا نريد فحص الرسائل جميعها التابعة للثريد الحالي . أما إذا أردت تحديد نافذة حالية فيجب أن تضع ال handle تبعها .. وهذه ال handle يمكن احضاره بسهولة عن طريق التابع GetSafeHwnd() أو مباشرة تستخدم تستخدم المتحول m_hWnd ولكن استخدام GetSafeHwnd أفضل لأن فيها الكود اللازم للتأكد من صحة النافذة وصحة الهاندل ...

Coding on the Cloud and for the Cloud!

My Blog

#7

شكرا لك أخي وأستاذي هاني

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

و شكرا للجميع

والسلام ، أخوكم

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

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