1

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

在此处输入图像描述

要添加的一件事是,由于颜色褪色(闪烁),按钮每秒进行大约 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();
    }
4

2 回答 2

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

当您的程序泄漏句柄时,您会遇到这种异常。Windows 允许您使用多达 10,000 个,然后它会生气并假设您的程序存在严重问题。您可以使用 Taskmgr.exe,“进程”选项卡看到的内容。查看 + 选择列并勾选 GDI 对象。还可能包括句柄和用户对象。如果在您使用程序时该数字持续上升,那么您有句柄泄漏。Kaboom 达到 10,000 时。

您对 Region 属性的使用是一个很好的选择。它不应该在 OnPaint() 中分配,这会产生大量的绘制事件。它只需要完成一次,你应该只在 OnHandleCreated() 中分配它,所以它只完成一次。

这本身将解决您将获得的快速异常。但是请确保您仍然没有句柄泄漏,您还有释放本机句柄的责任。您必须在释放窗口后调用 DeleteObject()。通过编写一个重复创建和处理控件的测试程序来测试它。并确保 GDI 对象计数保持稳定。喜欢使用 .NET Region 类,所以这一切都是自动的,减去为您创建圆角矩形的便利。

于 2013-07-22T13:23:38.237 回答
0

在我继续之前,我应该声明我不熟悉 gdi 库,所以这充其量只是一个猜测。对于因使用以下提供的任何信息而对软件、硬件、数据或理智造成的任何损害,我概不负责。

的值0表示p调用CreateRoundedRectRgn失败。从函数名称来看,它听起来像是创建了一个区域,并返回了一个指向其在内存中的位置的句柄,正如文档所说,您应该使用它DeleteObject来删除不再使用的区域。

这会向我暗示(同样,这只是一个猜测)gdi 库用于创建区域的任何资源(内存或地址空间)都将被用完,例如,因此 CreateRegion 调用失败。

您有两个选择:要么不经常创建区域(即创建控件时创建一次,然后如果它移动),或者使用DeleteObject在您的 Paint 方法结束时删除区域。IDisposable这对于块中的,可能是一个很好的用途using

于 2013-07-22T13:02:22.783 回答