PDA

View Full Version : مشکل کند بودن با WM_MOUSEMOVE



pswin.pooya
چهارشنبه 22 دی 1389, 20:26 عصر
سلام
من دارم یه برنامه MFC SDI می نویسم. برای view یه هندلر WM_MOUSEMOVE تعریف کردم. مشکل اینه که این پیام ویندوز مثل یه machine gun عمل میکنه و کوچکترین حرکت ماوس 10 ها پیام WM_MOUSEMOVE تولید میکنه. و نتیجتا توی این تابع من view رو invalide میکنم که باعث میشه 100ها بار تابع OnDraw فراخوانی بشه و سرعت برنامه کم بشه.

من یادم هستش که یه زمانی تو یکی از این فروم های خارجی یه تابع ویندوز رو دیده بودم که پیامهای تکراری مثل هم رو (مثل WM_MOUSEMOVE) رو که داخل صف قرار دارن حذف میکنه و تنها آخرین پیام رو نگه میداره. فکر کنم اینکار به باعث افزایش سرعت برنامه من بشه. کسی میدونه اون تابع چیه یا اینکه چه شکلی میشه توی MFC اینکار رو کرد.

mehdi.mousavi
پنج شنبه 23 دی 1389, 17:35 عصر
سلام من دارم یه برنامه MFC SDI می نویسم. برای view یه هندلر WM_MOUSEMOVE تعریف کردم. مشکل اینه که این پیام ویندوز مثل یه machine gun عمل میکنه و کوچکترین حرکت ماوس 10 ها پیام WM_MOUSEMOVE تولید میکنه. و نتیجتا توی این تابع من view رو invalide میکنم که باعث میشه 100ها بار تابع OnDraw فراخوانی بشه و سرعت برنامه کم بشه. من یادم هستش که یه زمانی تو یکی از این فروم های خارجی یه تابع ویندوز رو دیده بودم که پیامهای تکراری مثل هم رو (مثل WM_MOUSEMOVE) رو که داخل صف قرار دارن حذف میکنه و تنها آخرین پیام رو نگه میداره. فکر کنم اینکار به باعث افزایش سرعت برنامه من بشه. کسی میدونه اون تابع چیه یا اینکه چه شکلی میشه توی MFC اینکار رو کرد.

سلام.
شما چرا توی WM_MOUSEMOVE صفحه رو Invalidate می کنید؟ طبیعتا این کار همونطور که توضیح دادید، برنامه رو به زانو در میاره. (البته این مساله به رویه Paint شما هم میتونه ارتباط داشته باشه). چند روش به ذهنم میاد که میشه مشکل رو رفع کرد، اما خودتون باید آزمایشش کنید چون من فرصت اینکارو ندارم:


با تابع PeekMessage ببینید آیا پیامی در صف وجود داره یا خیر. اگر وجود داشت و اون پیام WM_MOUSEMOVE بود، توی یه حلقه با PeekMessage (در حالیکه پارامتر آخر رو PM_REMOVE میذارید)، کلیه WM_MOUSEMOVE های "متوالی" رو از صف خارج کنید.
میتونید یه Timer بذارید و تا وقتی Expire نشده، Invalidate نکنید. هر بار هم که WM_MOUSEMOVE رو دریافت می کنید، Timer خودتون رو Reset کنید. بدین ترتیب، Expire شدن تایمر به معنای نیاز به Invalidate کردن صفحه هستش. اینطوری تا وقتی Mouse در حال حرکت هستش صفحه Invalidate نمیشه، اما تا از حرکت ایستاد (و بطور مثال، 100 میلی ثانیه از توقف حرکت Mouse گذشت)، اونوقت صفحه Invalidate میشه.
می تونید با استفاده از یک Boolean Flag بازهم WM_MOUSEMOVE های اضافی رو دور بزنید. به این ترتیب که Flag ای رو در Window Procedure اتون Reset می کنید (FALSE). سپس، هر وقت WM_MOUSEMOVE رو گرفتید ابتدا Flag مزبور رو بررسی میکنید. اگر TRUE بود، یعنی هنوز کار Invalidate شدن صفحه تموم نشده، پس مجددا نمیگید Invalidate و این WM_MOUSEMOVE رو نادیده میگیرید. اما اگر FALSE بود، یه Custom Message به Main Thread ارسال می کنید و Flag مزبور رو TRUE می کنید. در نهایت توی اون Custom Message Handler خودتون می تونید Flag مزبور رو FALSE کنید. اینطوری، کاربر هر چقدر هم که Mouse رو تکون بده، تا وقتی عملیات Invalidate کردن قبلی تموم نشده، Invalidate جدیدی رخ نمیده.
...

موفق باشید.

pswin.pooya
جمعه 24 دی 1389, 09:25 صبح
سلام
ممنونم. من از همون تایمر استفاده کردم به شکی که هر 100 میلی ثانیه یکبار صفحه رو رسم میکنم. (اینبار با OpenGL).

اما اینکار به نظرم اصولی نیستش. یعنی باید هر وقت که لازمه صفحه دوباره رسم شه. متاسفانه منم وقت ندارم باید فورا پروژه ترم رو تحویل بدم. اما یادم میاد یه زمانی که رو انجین کار می کردم این مشکل رو داشتم که حرکت ماوس رو صفحه باعث پایین اومدن فریم ریت می شد. توی GameDev دنبالش گشتم و یه تابع رو پیدا کردم که مسیجهای مشابه رو حذف می کرد اون رو داخل انجین گذاشتم و جواب داد اما متاسفانه با فرمت اشتباهی ...