我制作了一个带有圆边的自定义按钮,我使用CreateRoundRectRgn
来实现这一点,在paint事件中调用它来围绕所有边缘,当我运行我的程序时一切正常,直到大约一分钟后,然后我得到以下异常(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();
}
答案 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
。