أين CWinApp::OnIdle في C؟

This article is available in English too, check it out here.

في MFC يمكنك استخدام الدالة CWinApp::OnIdle() لتنفيذ أوامر في وقت راحة البرنامج Idle-time Processing. بمعنى أنه عندما لا يكون هناك أي رسائل Messages يحتاج البرنامج إلى معالجتها فإن نظام التشغيل يقوم تلقائيا بتنفيذ الأوامر الموجودة في هذه الدالة CWinApp::OnIdle()، وبالطبع هذه الدالة ظاهرية Virtual بحيث يمكنك استخدامها في التصنيفات الخاصة بك المنحدرة من CWinApp.

وهذه الدالة لها التركيب التالي:

virtual BOOL OnIdle(LONG lCount);

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

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

المثال التالي يقوم برسم أشكال مستطيلة على الشاشة بطريقة عشوائية عندما يكون البرنامج في وقت الراحة Idle-time.

BOOL OnIdle(LONG lCount)
{
	CWinApp::OnIdle(lCount);    // <- NOTICE THIS
	CClientDC dc(m_pMainWnd);
	RECT rct;
	m_pMainWnd->GetClientRect(&rct);
	SetRect(&rct,
		rand() % rct.right,
		rand() % rct.bottom,
		rand() % rct.right,
		rand() % rct.bottom);
	dc.Rectangle(&rct);
	return TRUE;
}

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

لاحظ أيضا أنه يجب أن لا يكون الكود في دالة OnIdle() بسيط وقصيرحتى لا يسبب فشل البرنامج وتوقفه عن استقبال الرسائل وتنفيذها.

والآن، لنعد إلى موضوعنا الأصلي، هل تستطيع إستخدام هذه الدالة في لغة C؟ بالطبع إجابتك تكون لا، فإننا لا نستطيع استخدام MFC من خلال الـ C. إذا فما الحل؟

بما أن C لا تدعم MFC أو OnIdle()، فالحل هو أننا تقوم بإنشاء OnIdle() الخاصة بنا بطريقتنا.

الكود التالي يوضح طريقة بدائية لمحاكاة عمل OnIdle() في C. الكود تقوم باستخدامه بدلا من دوارة الرسائل Message Loop.

while (TRUE) {
	if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
		// if a quit message
		if (WM_QUIT == msg.message)
			break; // exit the loop
		// process other messages
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	else {	// no messages are waiting
		// do some idle processing
	}
}

أهم دالة في الكود السابق هي PeekMessage() والتي تقوم بإرجاع قيمة تساوي TRUE إن كانت هناك رسالة جاهزة للتنفيذ أو FALSE إن لم تكن هناك رسالة موجودة في صف الرسائل Message Queue. وفي الحالة الثانية، فإن الكود الخاص بوقت الراحة الخاص بالبرنامج ينفذ.

والآن، إلى مثال أكثر تقدما، الكود التالي يقوم بعمل محاكاة كاملة لدالة الـ OnIdle() ولكن في C:

BOOL OnIdle(LONG lCount);
int WINAPI WinMain(. . .)
{
	MSG msg;
	LONG lCount;
	. . .
		while (TRUE) {
			if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
				// found a message, resetting
				lCount = 0;
				if (WM_QUIT == msg.message)
					break;
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else {
				if (lCount >= 0) {
					if (!OnIdle(lCount)) {
						// set a flag indicates
						// no further OnIdle
						// calls till a new
						// session
						lCount = -1;
					}
					// increment the counter
					lCount++;
				}
			}
		}
		return msg.wParam;
}
BOOL OnIdle(LONG lCount)
{
	/*
	do some processing
	*/
	return FALSE;
}

هنا لاحظ أننا استخدمنا عدادا لحساب قيمة lCount. راجع الملاحظات Comments الموجودة داخل الكود.

انتهى الدرس. دمتم بأطيب حال!

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

اخترنا لك:

أحدث المواضيع:

هل أعجبتك؟ شارك بها...