GetRoundedRegion异常

时间:2013-07-22 12:27:59

标签: c# gdi+ gdi system.drawing

我制作了一个带有圆边的自定义按钮,我使用CreateRoundRectRgn来实现这一点,在paint事件中调用它来围绕所有边缘,当我运行我的程序时一切正常,直到大约一分钟后,然后我得到以下异常(p = 0的值):

enter image description here

要添加的一件事是,由于颜色褪色(闪烁),按钮每秒大约会发生50次绘画事件

这是我的油漆事件:

 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();
    }

2 个答案:

答案 0 :(得分:1)

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

当程序泄漏句柄时,会出现这种异常。 Windows允许你使用多达10,000个,然后它变得阴沉,并假设你的程序有一些严重错误。使用Taskmgr.exe,Processes选项卡可以看到的内容。查看+选择列并勾选GDI对象。可能还包括句柄和用户对象。如果在您使用程序时该数字一直在增加,那么您会出现句柄泄漏。 Kaboom达到10,000时。

您对Region属性的使用是一个很好的选择。它不应该在OnPaint()中分配,它可以创建一个paint事件风暴。它只需要完成一次,你应该只在OnHandleCreated()中分配它,所以只做一次。

这本身将解决你将获得的快速例外。但是请确保您仍然没有手柄泄漏,您还有责任释放本机手柄。在处理窗口后,您必须对DeleteObject()进行pinvoke。通过编写重复创建和配置控件的测试程序来测试。并确保GDI对象计数保持稳定。赞成使用.NET Region类,因此这是全自动的,减去了为您创建圆角矩形的便利。

答案 1 :(得分:0)

在继续之前,我应该声明我不熟悉gdi库,所以这是最好的猜测。对于因使用以下任何信息而导致的软件,硬件,数据或理智造成的任何损害,我将不承担任何责任。

0的值p表示对CreateRoundedRectRgn的调用失败。从函数名称,它听起来像创建一个区域,并返回其在内存中的位置的句柄,因为the documentation表示您应该使用DeleteObject删除您不再使用的区域。

这对我(再次,这只是一个猜测)建议,gdi库用于创建区域的任何资源都被用尽(例如,内存或地址空间),因此CreateRegion调用失败。 / p>

您可以从这里选择两个选项:要么不经常创建区域(例如,一旦创建控件,然后再移动),或者使用DeleteObject删除最后的区域你的Paint方法。这可能适用于IDisposable块中的using