GDI+और C++ के साथ झिलमिलाहट को कम करें




windows (4)

आप डीडी को लिखने के लिए जीडीआई + के बजाय पुराने जमाने वाले जीडीआई का उपयोग करने की कोशिश कर सकते हैं, खासकर जब आप पहले ही छवि को बफर कर रहे हैं बिटमैप :: लॉकबिट्स का उपयोग करें, कच्चे बिटमैप डेटा तक पहुंचने के लिए, एक बिटमैपिनएफ संरचना बनाएं, और बिटमैप प्रदर्शित करने के लिए SetDIBitsToDevice का उपयोग करें।

मैं एक सी + + / एमएफसी अनुप्रयोग में जीडीआई + का उपयोग कर रहा हूं और जब भी खिड़की का आकार बदल दिया जाता है तो मैं झिलमिलाहट से बचने में असमर्थ हूं।

मैंने पहले से ही इन चरणों का प्रयास किया है:

  • ऑन OnEraseBkGnd() पर TRUE लौटाया;
  • OnCtlColor() पर शून्य लौटा;
  • इस कोड के अनुसार डबल बफरिंग का इस्तेमाल किया गया:

void vwView::OnDraw(CDC* pDC) 
{
   CRect rcClient;
   GetClientRect(rcClient);

   Bitmap bmp(rcClient.Width(), rcClient.Height());
   Graphics graphics(&bmp);

   graphics.DrawImage(m_image, rcClient.left, rcClient.top);

   Graphics grph(pDC->m_hDC);
   grph.DrawImage(&bmp, 0, 0);
}

क्या मुझसे कुछ गलत हो रही है? या इस लक्ष्य को हासिल करने का एक और तरीका है?


क्या इस पर बच्चे की खिड़कियां हैं? खिड़की प्रबंधक एक पृष्ठभूमि संदेश को WM_ERASEBKGND भेजकर अपनी पृष्ठभूमि को मिटाने के लिए पैरेंट विंडो को प्राप्त कर लेता है, फिर यह एक wM_PAINT संदेश भेजता है - संभवतः इस नक्शे को आपके wx :: OnDraw विधि फिर यह प्रत्येक बच्चे को नियंत्रित करता है और खुद को पेंट करने के लिए उन्हें मिलता है।

अगर यह आपका परिदृश्य है ... विस्टा का नया ऐरो का उपयोग आपकी समस्या को हल करेगा जैसा कि एयरो डेस्कटॉप विंडो मैनेजर विंडो को स्वचालित रूप से कंपोज़िशन करता है पुरानी विंडो प्रबंधक के साथ यह एक पिता


झिलमिलाहट से पूरी तरह से बचने के लिए, आपको स्क्रीन अपडेट के बीच अंतराल में सभी ड्राइंग को पूरा करना होगा। विंडोज सामान्य विंडो पेंटिंग के लिए यह पूरा करने के किसी भी आसान साधन प्रदान नहीं करता है (विस्टा डीडब्ल्यूएम के माध्यम से समग्र ड्राइंग प्रदान करता है, लेकिन यह Vista पर चलने वाले सिस्टमों पर भी निर्भर नहीं हो सकता है)। इसलिए, झिलमिलाहट को कम करने के लिए सबसे अच्छा आप जितनी जल्दी हो सके उतना जल्दी आकर्षित कर सकते हैं (रीफ्रेश चक्र के भीतर सभी ड्राइंग को पूरा करने की संभावना बढ़ाकर फाड़ को कम करना ), और ओवरड्राव से बचें (स्क्रीन का आरेखण हिस्सा और उसके बाद कुछ और करना शीर्ष: एक आंशिक रूप से तैयार की गई स्क्रीन के साथ उपयोगकर्ता को प्रस्तुत करने के जोखिम)।

आइए अब तक प्रस्तुत तकनीकों पर चर्चा करें:

  • क्या- ऑन - इज़ेकबंक () : कुछ भी नहीं है- खिड़की के अमान्य क्षेत्र को खिड़की के पृष्ठभूमि रंग से भरने से रोककर अधिक से अधिक आकर्षित करने में मदद करता है डबल-बफर आरेखण के मामले में, जब आप WM_PAINT के दौरान फिर से पूरे क्षेत्र को फिर से आकर्षित करेंगे, तब उपयोगी होगा ... लेकिन अपने WM_PAINT विधि के बाद ड्राइंग को रोकने से ओवरड्राव से बचने पर नोट्स देखें।

  • OnCtlColor () के लिए शून्य प्राप्त करना: यह वास्तव में कुछ भी नहीं करना चाहिए ... जब तक कि आपके पास आपके फ़ॉर्म पर बाल नियंत्रण नहीं है उस स्थिति में, अपने WM_PAINT विधि के बाद ड्राइंग को रोकने के बजाय ओवरड्राव से बचने पर नोट्स देखें

  • डबल buffered ड्राइंग : वास्तविक बिट स्क्रीन पर ड्राइंग को एक बिट बीएलटीटी में कम करके, फाड़ने से बचने में मदद करता है (और संभवत: अच्छी तरह से ओवरड्राउड) । हालांकि ड्राइंग के लिए आवश्यक समय को नुकसान पहुंचा सकता है: हार्डवेयर त्वरण का उपयोग नहीं किया जा सकता है (हालांकि GDI + के साथ, किसी भी हार्डवेयर-सहायतायुक्त ड्राइंग की संभावना काफी पतली है), एक ऑफ-स्क्रीन बिटमैप बनाया जाना चाहिए और प्रत्येक रेड्रा के लिए भरना होगा, और प्रत्येक रेड्रा के लिए संपूर्ण विंडो को फिर से प्रकाशित किया जाना चाहिए कुशल डबल बफरिंग पर नोट्स देखें

  • बिट बीएलटी के लिए जीडीआई + के बजाय जीडीआई कॉल का उपयोग करना : यह अक्सर अच्छा विचार है - Graphics::DrawImage() बहुत धीमा हो सकता है मैंने कुछ सिस्टम पर सामान्य GDI BitBlt() कॉल को तेजी से प्राप्त किया है। इस के साथ खेलें, लेकिन कुछ अन्य सुझावों को पहले प्रयास करने के बाद।

  • विंडो श्रेणी शैलियों से बचना, जो प्रत्येक आकार में पूर्ण रेड्राऊण्ड को मजबूर करते हैं ( CS_VREDRAW , CS_HREDRAW ) : इससे मदद मिलेगी, लेकिन केवल तभी जब आपको आकार बदलता है, तब पूरी विंडो को फिर से भरने की आवश्यकता नहीं होती है

अपने WM_PAINT विधि से पहले चित्र को रोकने से ओवरड्राव से बचने पर नोट्स

जब एक खिड़की के सभी या एक हिस्से को अमान्य किया जाता है, तो इसे मिटा दिया जाएगा और repainted होगा। जैसा कि पहले से ही उल्लेख किया गया है, यदि आप पूरे अमान्य क्षेत्र को फिर से रंगना चाहते हैं, तो आप मिट सकते हैं। हालांकि , अगर आप एक बच्चे की खिड़की के साथ काम कर रहे हैं, तो आपको यह सुनिश्चित करना होगा कि माता-पिता विंडो स्क्रीन के आपके क्षेत्र को मिटा नहीं रहे हैं। WS_CLIPCHILDREN शैली को सभी मूल विंडो पर सेट किया जाना चाहिए - यह बाल विंडो (आपके दृश्य सहित) द्वारा खींचा जाने वाले क्षेत्रों पर कब्जा कर लिया जाएगा।

अपने WM_PAINT विधि के बाद ड्राइंग को रोकने के कारण ओवरड्राव से बचने पर नोट्स

यदि आपके पास आपके प्रपत्र पर होस्ट किए गए किसी भी बच्चे के नियंत्रण हैं, तो आप उन पर ड्राइंग से बचने के लिए WS_CLIPCHILDREN शैली का उपयोग करना चाहते हैं (और बाद में उनके द्वारा खींचा जा रहा है।) ध्यान रखें, यह बिटबटल नियत की गति को कुछ हद तक प्रभावित करेगा

कुशल डबल-बफरिंग पर नोट्स

अभी, आप हर बार व्यू स्वयं को खींचते समय एक नई बैक-बफर छवि बना रहे हैं बड़ी खिड़कियों के लिए, यह आवंटित और रिलीज़ होने वाली स्मृति की एक महत्वपूर्ण राशि का प्रतिनिधित्व कर सकता है, और महत्वपूर्ण प्रदर्शन समस्याओं का परिणाम देगा । मैं आपके दृश्य ऑब्जेक्ट में गतिशील रूप से आवंटित बिटमैप रखने की अनुशंसा करता हूं, इसे आपके दृश्य के आकार से मिलान करने के लिए पुनः आवंटित करना आवश्यक है।

ध्यान दें कि जब विंडो का आकार बदल दिया जा रहा है, तो इसका परिणाम वर्तमान सिस्टम के रूप में बहुत से आवंटन में होगा, क्योंकि प्रत्येक नए आकार के लिए इसे पूरा करने के लिए आवंटित किए जाने वाले नए बैक बफर बिटमैप की आवश्यकता होगी - आप कुछ हद तक दर्द को कम करने के लिए आयाम बढ़ा सकते हैं 4, 8, 16, आदि के अगले सबसे बड़े मल्टीपल के लिए, आप आकार में प्रत्येक छोटे परिवर्तन पर फिर से आवंटित करने से बचने की इजाजत देते हैं।

ध्यान दें, यदि विंडो के आकार को पिछली बार जब आप बैक बफर में रेंडर करते हैं, तब से बदलाव नहीं हुआ है, तब आपको इसे फिर से रेंडर करने की ज़रूरत नहीं है जब खिड़की अवैध है - बस पहले से गाया हुआ ब्लाट बाहर छवि पर स्क्रीन।

साथ ही, एक बिटमैप आवंटित करें जो कि स्क्रीन की बिट गहराई से मेल खाता है। आपके द्वारा वर्तमान में उपयोग किए जा रहे Bitmap लिए निर्माता 32 बीपीपी, एआरजीबी-लेआउट पर डिफ़ॉल्ट होगा; अगर यह स्क्रीन से मेल नहीं खाता है, तो इसे परिवर्तित करना होगा। एक मिलान बिटमैप प्राप्त करने के लिए GDI विधि CreateCompatibleBitmap() का उपयोग करने पर विचार करें।

आखिरकार ... मैं आपका उदाहरण कोड मानता हूं कि, एक उदाहरण स्निपेट है लेकिन, अगर आप वास्तव में स्क्रीन पर मौजूदा छवि को प्रस्तुत करने से परे कुछ भी नहीं कर रहे हैं, तो आपको वास्तव में एक बैक बफर को बनाए रखने की आवश्यकता नहीं है - बस छवि से सीधे ब्लाट (और समय के आगे छवि का प्रारूप परिवर्तित करें स्क्रीन से मेल खाएं)


इस लिंक में कुछ उपयोगी जानकारी है: http://www.catch22.net/tuts/flicker-free-drawing

(मुझे पता है कि यह थ्रेड के लिए बहुत ही देर का अतिरिक्त है, लेकिन यह किसी के लिए है (जैसे मेरे) जो मेरे Win32 ऐप में झिलमिलाहट को कम करने के लिए देख रहे थे ...)







gdi+