उपयोगकर्ता नियंत्रण में फ़्लिकरिंग को कैसे ठीक करें


107

अपने आवेदन में मैं लगातार एक नियंत्रण से दूसरे पर जा रहा हूं। मैंने नहीं बनाया है। उपयोगकर्ता नियंत्रण, लेकिन नेविगेशन के दौरान मेरे नियंत्रण झिलमिलाहट हो जाते हैं। अपडेट होने में 1 या 2 सेकंड का समय लगता है। मैंने इसे सेट करने की कोशिश की

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); 
SetStyle(ControlStyles.DoubleBuffer, true);

लेकिन यह मदद नहीं की ... प्रत्येक नियंत्रण में अलग-अलग नियंत्रणों के साथ एक ही पृष्ठभूमि छवि है। तो इसके लिए क्या उपाय है ..
धन्यवाद।


ये कथन कहाँ हैं? आदर्श रूप से, उन्हें कंस्ट्रक्टर में डालें। क्या आपने UpdateStylesइन्हें सेट करने के बाद कॉल किया था ? यह बुरी तरह से प्रलेखित है, लेकिन कभी-कभी आवश्यक हो सकता है।
थॉमस

जवाबों:


306

यह उस तरह की झिलमिलाहट नहीं है जिसे डबल-बफरिंग हल कर सकती है। और न ही शुरुआत या निलंबित करें। आपके पास बहुत अधिक नियंत्रण हैं, BackgroundImage इसे बहुत खराब कर सकता है।

यह तब शुरू होता है जब UserControl स्वयं पेंट करता है। यह बैकग्राउंडइमेज को ड्रॉ करता है, जिसमें बाल नियंत्रण खिड़कियां जाती हैं, जहां छेद होते हैं। प्रत्येक बच्चे का नियंत्रण तब खुद को पेंट करने का संदेश देता है, वे अपनी खिड़की की सामग्री के साथ छेद में भर देंगे। जब आपके पास बहुत सारे नियंत्रण होते हैं, तो वे छेद कुछ समय के लिए उपयोगकर्ता को दिखाई देते हैं। वे आम तौर पर सफेद होते हैं, जब यह अंधेरा होता है तो BackgroundImage के साथ बुरी तरह विपरीत होता है। या वे काले हो सकते हैं यदि फॉर्म में अपनी Opacity या TransparencyKey प्रॉपर्टी सेट है, तो किसी भी चीज़ के साथ बुरी तरह से विपरीत।

यह विंडोज फॉर्म्स की एक बहुत ही मौलिक सीमा है, यह विंडोज विंडोज को रेंडर करने के तरीके से अटका हुआ है। WPF btw द्वारा निर्धारित, यह बच्चे के नियंत्रण के लिए खिड़कियों का उपयोग नहीं करता है। आप जो चाहते हैं, वह पूरे फॉर्म को डबल-बफ़र कर रहा है, जिसमें चाइल्ड कंट्रोल भी शामिल है। यह संभव है, समाधान के लिए इस धागे में मेरा कोड जांचें । हालांकि इसके साइड-इफेक्ट्स हैं, और यह वास्तव में पेंटिंग की गति को नहीं बढ़ाता है। कोड सरल है, इसे अपने रूप में पेस्ट करें (उपयोगकर्ता नियंत्रण नहीं):

protected override CreateParams CreateParams {
  get {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    return cp;
  }
} 

कई चीजें हैं जो आप पेंटिंग की गति को बेहतर बनाने के लिए कर सकते हैं, इस बिंदु पर कि फ़्लिकर अब ध्यान देने योग्य नहीं है। BackgroundImage से निपटने के द्वारा शुरू करें। स्रोत की छवि बड़ी होने और नियंत्रण में फिट होने के लिए सिकुड़ने की आवश्यकता होने पर वे वास्तव में महंगे हो सकते हैं । BackgroundImageLayout प्रॉपर्टी को "टाइल" में बदलें। यदि वह ध्यान देने योग्य गति देता है, तो अपने पेंटिंग प्रोग्राम पर वापस जाएं और छवि को आकार दें ताकि विशिष्ट नियंत्रण आकार के साथ बेहतर मिलान हो सके। या UC के OnResize () विधि में छवि की एक उचित आकार की प्रतिलिपि बनाने के लिए कोड लिखें, ताकि इसे नियंत्रण repaints को हर बार रीसाइज़ न करना पड़े। उस प्रति के लिए Format32bppPArgb पिक्सेल प्रारूप का उपयोग करें, यह किसी भी अन्य पिक्सेल प्रारूप की तुलना में लगभग 10 गुना तेजी से प्रस्तुत करता है।

अगली चीज जो आप कर सकते हैं, वह छेद को ध्यान देने योग्य होने और छवि के साथ बुरी तरह से विपरीत होने से रोक सकता है। आप UC के लिए WS_CLIPCHILDREN स्टाइल फ्लैग को बंद कर सकते हैं , वह फ़्लैग जो उस UC को उस क्षेत्र में पेंटिंग करने से रोकता है जहाँ बच्चा नियंत्रण करता है। इस कोड को UserControl के कोड में पेस्ट करें:

protected override CreateParams CreateParams {
  get {
    var parms = base.CreateParams;
    parms.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN
    return parms;
  }
}

बाल नियंत्रण अब पृष्ठभूमि की छवि के शीर्ष पर खुद को चित्रित करेगा। आप अभी भी उन्हें एक-एक करके खुद को रंगते हुए देख सकते हैं, लेकिन बदसूरत मध्यवर्ती सफेद या काला छेद दिखाई नहीं देगा।

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


मेरे लिए WS_CLIPCHILDREN बेहतर उपयोगकर्ता अनुभव को बंद करें।
महेश

बिल्कुल सही! .. बहुत बहुत धन्यवाद
AlejandroAlis

8

यह एक वास्तविक मुद्दा है, और हंस हंसंत ने जो जवाब दिया, वह झिलमिलाहट को बचाने के लिए बहुत अच्छा है। हालांकि, वहाँ दुष्प्रभाव हैं जैसा कि उन्होंने उल्लेख किया है, और वे बदसूरत (यूआई बदसूरत) हो सकते हैं। जैसा कि कहा गया है, "आप WS_CLIPCHILDRENयूसी के लिए स्टाइल फ्लैग को बंद कर सकते हैं ", लेकिन यह केवल एक यूसी के लिए बंद हो जाता है। मुख्य रूप पर घटकों में अभी भी समस्याएं हैं।

उदाहरण के लिए, एक पैनल स्क्रॉल बार पेंट नहीं करता है, क्योंकि यह तकनीकी रूप से बाल क्षेत्र में है। हालाँकि चाइल्ड कंपोनेंट स्क्रॉल बार नहीं खींचता है, इसलिए यह माउस के ऊपर (या किसी अन्य घटना के ट्रिगर होने) तक पेंट नहीं हो पाता है।

इसके अलावा, एनिमेटेड आइकन (एक प्रतीक्षा लूप में आइकन बदलते) काम नहीं करते हैं। आइकन पर हटाने tabPage.ImageKeyसे अन्य टैब टैब को उचित रूप से आकार / पुनरावृत्ति नहीं होती है।

इसलिए मैं WS_CLIPCHILDRENप्रारंभिक पेंटिंग को बंद करने का एक तरीका ढूंढ रहा था ताकि मेरा फॉर्म अच्छी तरह से पेंट हो जाए, या बेहतर होगा, फिर भी बहुत सारे घटकों के साथ मेरे फॉर्म को आकार देते समय इसे चालू करें।

चाल को CreateParamsवांछित WS_EX_COMPOSITED/WS_CLIPCHILDRENशैली के साथ कॉल करने के लिए एप्लिकेशन प्राप्त करना है। मुझे यहाँ एक हैक मिला ( https://web.archive.org/web/20161026205944/http://www.angryhacker.com/blog/archive/2010/07/21/how-to-get-rid-of- झिलमिलाहट-ऑन-विंडोज-फॉर्म-Applications.aspx ) और यह बहुत अच्छा काम करता है। धन्यवाद एंग्रीहैकर!

मैंने TurnOnFormLevelDoubleBuffering()कॉल को फॉर्म ResizeBeginईवेंट में रखा और TurnOffFormLevelDoubleBuffering()फॉर्म ResizeEnd ईवेंट में कॉल करें (या WS_CLIPCHILDRENइसे शुरू में ठीक से पेंट करने के बाद छोड़ दें ।)

    int originalExStyle = -1;
    bool enableFormLevelDoubleBuffering = true;

    protected override CreateParams CreateParams
    {
        get
        {
            if (originalExStyle == -1)
                originalExStyle = base.CreateParams.ExStyle;

            CreateParams cp = base.CreateParams;
            if (enableFormLevelDoubleBuffering)
                cp.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED
            else
                cp.ExStyle = originalExStyle;

            return cp;
        }
    }

    public void TurnOffFormLevelDoubleBuffering()
    {
        enableFormLevelDoubleBuffering = false;
        this.MaximizeBox = true;
    }

आपके कोड में TurnOnFormLevelDoubleBuffering () विधि शामिल नहीं है ...
Dan W

@DanW इस उत्तर में पोस्ट किए गए URL पर एक नज़र डालें ( गुस्से में ।.com
log_archive

इस उत्तर में लिंक मृत प्रतीत होता है। मैं समाधान के बारे में उत्सुक हूं, क्या आपके पास एक और उदाहरण के लिए लिंक है?
प्रैट हिंड्स

6

यदि आप नियंत्रण में कोई कस्टम पेंटिंग कर रहे हैं (अर्थात ऑनपेंट को ओवरराइड कर रहे हैं) तो आप डबल बफ़रिंग की कोशिश कर सकते हैं।

Image image;
protected override OnPaint(...) {
    if (image == null || needRepaint) {
        image = new Bitmap(Width, Height);
        using (Graphics g = Graphics.FromImage(image)) {
            // do any painting in image instead of control
        }
        needRepaint = false;
    }
    e.Graphics.DrawImage(image, 0, 0);
}

और एक संपत्ति के साथ अपने नियंत्रण को अमान्य करें NeedRepaint

अन्यथा SuspendLayout और ResumeLayout के साथ उपरोक्त उत्तर शायद वही है जो आप चाहते हैं।


यह डबलबफ़र अनुकरण करने के लिए एक रचनात्मक विधि है!। आप if (image != null) image.Dispose();इससे पहले जोड़ सकते हैंimage = new Bitmap...
S.Serpooshan

3

2

मुख्य रूप या उपयोगकर्ता नियंत्रण पर, जहां पृष्ठभूमि छवि रहती है, BackgroundImageLayoutसंपत्ति को सेट करें Centerया Stretch। जब उपयोगकर्ता नियंत्रण प्रदान कर रहा है तो आपको एक बड़ा अंतर दिखाई देगा।


2

मैंने इसे एक टिप्पणी के रूप में जोड़ने की कोशिश की लेकिन मेरे पास पर्याप्त अंक नहीं हैं। यह केवल एक चीज है जिसने कभी मेरी चंचल समस्याओं को मदद की है ताकि उसके पोस्ट के लिए हंस को बहुत धन्यवाद। किसी ऐसे व्यक्ति के लिए जो सी + + बिल्डर की तरह अपने यहाँ अनुवाद का उपयोग कर रहा है

CreateParams घोषणा को अपने आवेदन के मुख्य रूप में जोड़ें। h फ़ाइल उदा

class TYourMainFrom : public TForm
{
protected:
    virtual void __fastcall CreateParams(TCreateParams &Params);
}

और इसे अपने .cpp फ़ाइल में जोड़ें

void __fastcall TYourMainForm::CreateParams(TCreateParams &Params)
{
    Params.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    TForm::CreateParams(Params);
}

2

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

यदि आप एक कस्टम नियंत्रण बना रहे हैं, तो आप इस ध्वज को अपने ctor में जोड़ना चाह सकते हैं:

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

वैकल्पिक रूप से आप इस कोड का उपयोग अपने फॉर्म / नियंत्रण में कर सकते हैं:

foreach (Control control in Controls)
{
    typeof(Control).InvokeMember("DoubleBuffered",
        BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
        null, control, new object[] { true });
}

हम प्रपत्र / नियंत्रण में सभी नियंत्रणों के माध्यम से पुनरावृत्ति करते DoubleBufferedहैं और उनकी संपत्ति तक पहुंच प्राप्त करते हैं और फिर हम प्रपत्र को डबल बफ़र करने के लिए प्रत्येक नियंत्रण को सही करने के लिए इसे बदल देते हैं। जिस कारण से हम यहाँ परावर्तन करते हैं, वह यह है कि कल्पना कीजिए कि आपके पास एक ऐसा नियंत्रण है जिसमें बच्चे के नियंत्रण हैं जो सुलभ नहीं हैं, इस तरह, भले ही वे निजी नियंत्रण हों, फिर भी हम उनकी संपत्ति को सही में बदल देंगे।

डबल बफरिंग तकनीक के बारे में अधिक जानकारी यहां पाई जा सकती है

एक और संपत्ति है जिसे मैं आमतौर पर इस समस्या को हल करने के लिए ओवरराइड करता हूं:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams parms = base.CreateParams;
        parms.ExStyle |= 0x00000020; // WS_EX_COMPOSITED
        return parms;
    }
}

WS_EX_COMPOSITED - डबल-बफ़रिंग का उपयोग करके नीचे-से-ऊपर पेंटिंग ऑर्डर में एक खिड़की के सभी वंशज पेंट।

आप यहां इन शैली के झंडे के अधिक पा सकते हैं ।

उम्मीद है की वो मदद करदे!


1

हंस ने जो जवाब दिया उसे जोड़ने के लिए बस:

(TLDR संस्करण: पारदर्शिता आपके विचार से भारी है, हर जगह केवल ठोस रंगों का उपयोग करें)

यदि WS_EX_COMPOSITED, DoubleBuffered और WS_CLIPCHILDREN ने आपकी झिलमिलाहट को हल नहीं किया (मेरे लिए WS_CLIPCHILDREN ने इसे और भी बदतर बना दिया), तो यह आज़माएं: अपने सभी नियंत्रणों और सभी कोडों से गुज़रें और जहाँ भी आपके पास BackColor, ForeColor, या पारदर्शिता के लिए कोई पारदर्शिता या अर्ध-पारदर्शिता हो, किसी भी अन्य रंग, बस इसे हटा दें, केवल ठोस रंगों का उपयोग करें। ऐसे मामलों में जहां आपको लगता है तुम सिर्फ के अधिकांश में है पारदर्शिता का उपयोग करने के लिए, आप ऐसा नहीं करते। अपने कोड और नियंत्रणों को फिर से डिज़ाइन करें, और ठोस रंगों का उपयोग करें। मेरे पास भयानक, भयानक चंचलता थी और कार्यक्रम सुस्त चल रहा था। एक बार जब मैंने पारदर्शिता को हटा दिया तो यह काफी बढ़ गया, और 0 झिलमिलाहट है।

संपादित करें: आगे जोड़ने के लिए, मुझे पता चला कि WS_EX_COMPOSITED को विंडो-वाइड होना जरूरी नहीं है, इसे केवल विशिष्ट नियंत्रणों पर लागू किया जा सकता है! इससे मुझे बहुत परेशानी का सामना करना पड़ा। बस आपको जो भी नियंत्रण की आवश्यकता है, उससे विरासत में मिला एक कस्टम नियंत्रण, और WS_EX_COMPOSITED के लिए पहले से ही पोस्ट किए गए ओवरराइड को पेस्ट करें। इस तरह से आपको इस स्तर पर केवल निम्न स्तर के डबल-बफर मिलते हैं, बाकी एप्लिकेशन में खराब साइड-इफेक्ट्स से बचते हैं!


0

मैं जानता हूं कि यह सवाल बहुत पुराना है, लेकिन मैं इस पर अपना अनुभव देना चाहता हूं।

मुझे .NET 4.0 का उपयोग करके Tabcontrolओवररेटेड OnPaintऔर / या OnPaintBackGroundविंडोज 8 में एक फॉर्म में झिलमिलाहट के साथ बहुत सारी समस्याएं थीं ।

केवल लगता है कि काम किया गया है प्रयोग नGraphics.DrawImage में विधि OnPaint, ओवरराइड, दूसरे शब्दों में जब ड्रा सीधे किया गया था ग्राफिक्स के लिए द्वारा प्रदान की PaintEventArgs, यहां तक कि सभी आयत, गायब अस्थिरता पेंटिंग। लेकिन अगर DrawImageविधि को बुलाओ , यहां तक ​​कि एक क्लिप्ड बिटमैप ड्राइंग, (डबल बफ़रिंग के लिए बनाई गई) झिलमिलाहट दिखाई देती है।

आशा करता हूँ की ये काम करेगा!


0

मैंने इस झिलमिलाहट को ठीक किया और इस फ़ॉन्ट को ठीक किया , फिर मुझे अपने स्वयं के कोड को थोड़ा जोड़ना पड़ा पेंट पर एक टाइमर शुरू करने के लिए टैबकॉन्ट्रोल को ऑफस्क्रीन और वापस जाने पर, आदि।

तीनों इसे बनाते हैं:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class TabControlEx:TabControl
{
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    private const int WM_PAINT = 0x0f;
    private const int WM_SETFONT = 0x30;
    private const int WM_FONTCHANGE = 0x1d;
    private System.Drawing.Bitmap buffer;
    private Timer timer = new Timer();
    public TabControlEx()
    {
        timer.Interval = 1;
        timer.Tick += timer_Tick;
        this.SetStyle(ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
    }
    void timer_Tick(object sender, EventArgs e)
    {
        this.Invalidate();
        this.Update();
        timer.Stop();
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_PAINT) timer.Start();
        base.WndProc(ref m);
    }
    protected override void OnPaint(PaintEventArgs pevent)
    {
        this.SetStyle(ControlStyles.UserPaint, false);
        base.OnPaint(pevent);
        System.Drawing.Rectangle o = pevent.ClipRectangle;
        System.Drawing.Graphics.FromImage(buffer).Clear(System.Drawing.SystemColors.Control);
        if (o.Width > 0 && o.Height > 0)
        DrawToBitmap(buffer, new System.Drawing.Rectangle(0, 0, Width, o.Height));
        pevent.Graphics.DrawImageUnscaled(buffer, 0, 0);
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        buffer = new System.Drawing.Bitmap(Width, Height);
    }
    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        this.OnFontChanged(EventArgs.Empty);
    }
    protected override void OnFontChanged(EventArgs e)
    {
        base.OnFontChanged(e);
        IntPtr hFont = this.Font.ToHfont();
        SendMessage(this.Handle, WM_SETFONT, hFont, (IntPtr)(-1));
        SendMessage(this.Handle, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
        this.UpdateStyles();
    }
}

मैं निर्माता नहीं हूँ, लेकिन जो मुझे समझ में आया है कि बिटमैप सभी बग को दरकिनार करता है।

यह एकमात्र ऐसी चीज थी जो निश्चित रूप से मेरे लिए TabControl (प्रतीक के साथ) झिलमिलाहट को हल करती थी।

अंतर परिणाम वीडियो: वेनिला tabcontrol बनाम tabcontrolex

http://gfycat.com/FineGlitteringDeermouse

ps। आपको HotTrack = true सेट करने की आवश्यकता होगी, क्योंकि यह उस बग को भी ठीक करता है


-2

क्या आपने Control.DoubleBufferedसंपत्ति की कोशिश की ?

हो जाता है या यह दर्शाता है कि यह नियंत्रण झिलमिलाहट को कम करने या रोकने के लिए एक माध्यमिक बफर का उपयोग करके इसकी सतह को फिर से बनाना चाहिए या नहीं, यह दर्शाता है।

इसके अलावा इस और इस आ सकता है।


-9

किसी भी डबल बफरिंग की जरूरत नहीं है और वह सब सामान लोगों ...

एक सरल उपाय ...

यदि आप एमडीआई इंटरफेस का उपयोग कर रहे हैं, तो बस नीचे दिए गए कोड को मुख्य रूप में पेस्ट करें। यह पृष्ठों से सभी झिलमिलाहट को हटा देगा। हालाँकि कुछ पेज जिन्हें लोड करने के लिए अधिक समय की आवश्यकता होती है वे 1 या 2 सेकंड में दिखेंगे। लेकिन यह फ़्लिकरिंग पृष्ठ दिखाने से बेहतर है जिसमें प्रत्येक आइटम एक-एक करके आता है।

यह पूरे आवेदन के लिए एकमात्र सबसे अच्छा समाधान है। मुख्य रूप में रखने के लिए कोड देखें:

protected override CreateParams CreateParams {
  get {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    return cp;
  }
} 

12
तो, आप क्या कह रहे हैं कि हंस ने जो जवाब दो साल पहले दिया था, वह वास्तव में सही है? धन्यवाद, क्षितिज। यह वास्तव में बहुत उपयोगी है!
फर्नांडो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.