GetRoundedRegion exception

╄→гoц情女王★ 提交于 2019-12-11 12:29:44

问题


I made a custom button with rounded edges, i use CreateRoundRectRgn for this, in the paint event this is called to round all the edges, when i run my program everything works fine until after about one minute, then i get the following exception(the value of p = 0):

one thing to add is that the button is undergoing about 50 paint events per second because of a color fade (blinking)

this is my paint event:

 protected override void OnPaint(PaintEventArgs e)
    {
        this.SuspendLayout();

        this.Region = GetRoundedRegion(this.Width, this.Height);

        base.OnPaint(e);

        if (!this.Enabled)
            e.Graphics.Clear(this.DisabledColor);
        else if (Blinking)
            e.Graphics.Clear(Color.FromArgb(blinkingIntensity, this.BlinkColor));
        else if (this.Pressed)
            e.Graphics.Clear(this.PressedColor);
        else if (this.Selected)
            e.Graphics.Clear(this.SelectedColor);
        else
            e.Graphics.Clear(this.Color);


        using (Pen blackPen = new Pen(Color.FromArgb(150, Color.Black), 2))
        using (Pen whitePen = new Pen(Color.FromArgb(150, Color.Black), 2))
        {
            if (Pressed)
            {
                e.Graphics.DrawLines(blackPen, new[] { new Point(0, this.Height), new Point(0, 0), new Point(this.Width, 0) });
                e.Graphics.DrawArc(blackPen, new Rectangle(0, 0, _Radius, _Radius), 180, 90);

                e.Graphics.DrawLines(whitePen, new[] { new Point(0, this.Height - 2), new Point(this.Width - 2, this.Height - 2), new Point(this.Width - 2, 0) });
                e.Graphics.DrawArc(whitePen, new Rectangle(this.Width - 2 - _Radius, this.Height - 2 - _Radius, _Radius, _Radius), 0, 90);

                using (LinearGradientBrush lb = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), Color.FromArgb(150, Color.Black), Color.FromArgb(100, Color.White)))
                {
                    e.Graphics.FillRectangle(lb, 0, 0, this.Width, this.Height);
                }
            }
            else
            {
                e.Graphics.DrawLines(whitePen, new[] { new Point(0, this.Height), new Point(0, 0), new Point(this.Width, 0) });
                e.Graphics.DrawArc(whitePen, new Rectangle(0, 0, _Radius, _Radius), 180, 90);

                e.Graphics.DrawLines(blackPen, new[] { new Point(0, this.Height - 2), new Point(this.Width - 2, this.Height - 2), new Point(this.Width - 2, 0) });
                e.Graphics.DrawArc(blackPen, new Rectangle(this.Width - 2 - _Radius, this.Height - 2 - _Radius, _Radius, _Radius), 0, 90);

                using (LinearGradientBrush lb = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), Color.FromArgb(100, Color.White), Color.FromArgb(150, Color.Black)))
                {
                    e.Graphics.FillRectangle(lb, 0, 0, this.Width, this.Height);
                }
            }
        }

        int pressedoffset = 0;
        if (Pressed)
            pressedoffset = 2;

        int maxWidth = this.Width - 20;

        // Set up string.
        string measureString = Text;

        Font stringFont = Font;

        // Set maximum width of string.
        int stringWidth = this.Width - 20;

        SizeF stringSize = new SizeF();

        // Set string format.
        using (StringFormat newStringFormat = new StringFormat())
        {
            newStringFormat.FormatFlags = StringFormatFlags.DisplayFormatControl;

            stringSize = e.Graphics.MeasureString(measureString, stringFont, stringWidth, newStringFormat);
        }
        // Draw string to screen.
        if (CenterText)
            e.Graphics.DrawString(measureString, stringFont, Brushes.White, new PointF(((this.Width / 2) - (stringSize.Width / 2)) + pressedoffset, ((this.Height / 2) - (stringSize.Height / 2)) + pressedoffset));
        else
            e.Graphics.DrawString(measureString, stringFont, Brushes.White, new PointF(10 + pressedoffset, ((this.Height / 2) - (stringSize.Height / 2)) + pressedoffset));

        this.ResumeLayout();
    }

回答1:


    this.Region = GetRoundedRegion(this.Width, this.Height);

You get this kind of exception when your program leaks handles. Windows lets you use up to 10,000 of them, then it gets sulky and assumes there's something drastically wrong with your program. Something you can see with Taskmgr.exe, Processes tab. View + Select Columns and tick GDI Objects. Might as well include Handles and USER Objects. If that number keeps going up while you use your program then you have a handle leak. Kaboom when it reaches 10,000.

Your use of the Region property is an excellent candidate. It should not be assigned in OnPaint(), that can create a storm of paint events. It needs to be done only once, you should only ever assign it in OnHandleCreated() so it is done just once.

That in itself will fix the quick exception you'll get. But make sure you don't still have a handle leak, you also have the responsibility of releasing the native handle. You must pinvoke DeleteObject() after the window is disposed. Test that by writing a test program that repeatedly creates and disposes the control. And ensure the GDI Objects count is remains stable. Favor using the .NET Region class so this is all automatic, minus the convenience of getting a rounded rectangle created for you.




回答2:


Before I continue, I should state that I am not familiar with the gdi library, so this is a guess at best. I will not be held responsible for any damage to software, hardware, data or sanity that results in using any of the information provided below..

The value 0 for p indicates that the call to CreateRoundedRectRgn has failed. From the function name, it sounds like it creates a region, and returns a handle to its location in memory, as the documentation says you should use DeleteObject to delete a region you are no longer using.

That would suggest to me (and again, this is only a guess) that whatever resources the gdi library is using to create regions is being used up (memory or address space), for instance, hence the CreateRegion call fails.

You have two options from here: either don't create regions so often (i.e. once when you create the control, and then if it moves), or use DeleteObject to delete the region at the end of your Paint method. This might be a good use for an IDisposable, in a using block.



来源:https://stackoverflow.com/questions/17787573/getroundedregion-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!