我需要绘制一个整个表单大小的圆圈。我使用以下Paint事件处理程序创建了Form1:
private void Form1_Paint(object sender, PaintEventArgs e)
{
SolidBrush myBrush = new SolidBrush(Color.Black);
e.Graphics.FillEllipse(myBrush, 0, 0, this.ClientSize.Width, this.ClientSize.Height);
}
问题在于,当您更改表单的大小或最大化它时,绘图会被破坏。请帮我解决这个问题。抱歉,我在StackOverflow上找不到合适的主题。
答案 0 :(得分:4)
对像Form这样的容器控件的绘制进行了优化,它们只重绘了resize显示的窗口部分。换句话说,如果用户拖动右边缘或底边缘,那么当窗口变小时,根本不会重新绘制。一个小的重绘,如果它变得更大,只有窗口的一部分变得可见。
这通常非常合适,因为他们没有太多理由完全重绘自己,他们只画出他们的背景。当用户通过拖动角落来调整窗口大小时,这尤其重要,这可能会产生重绘请求的风暴。如果重新绘制速度很慢,那么它就会变得非常明显,移动鼠标会使动作变得“断断续续”,闪烁也会变得明显。
但是你关心,你需要来完全重绘椭圆,因为你在paint事件处理程序中使用了ClientSize属性。
这个优化是否打开是由控件的样式标志决定的,正如Sriram所指出的那样。关闭它是如此常见,以至于Winforms通过一个简单的属性公开了样式标志,以便更改它:
public Form1() {
InitializeComponent();
this.ResizeRedraw = true;
this.DoubleBuffered = true;
}
请注意DoubleBuffered属性,这是实际更改ControlStyles的便捷属性的另一个示例。您希望此功能可以抑制窗口显示的闪烁。首先绘制背景,擦除椭圆,然后重新绘制椭圆。
您的代码中存在另一个非常严重的问题,SolidBrush是一个一次性类。处置对象是可选的,但是为System.Drawing对象跳过这个是非常不明智的。如果您经常调整窗口大小10000次,那么您的程序将崩溃。听起来很多,但是当你将ResizeRedraw设置为true时,它不会产生大量的重绘。只有垃圾收集器可以让你摆脱困境,它不会在这样的简单程序中。修正:
protected override void OnPaint(PaintEventArgs e) {
using (var brush = new SolidBrush(this.ForeColor)) {
e.Graphics.FillEllipse(brush, 0, 0, this.ClientSize.Width, this.ClientSize.Height);
}
base.OnPaint(e);
}
顺便说一句,不通过按照另一篇文章中的建议保持画笔来优化它。创建画笔非常便宜,大约需要一微秒。但是,它太昂贵了,它被分配在一个由桌面上运行的所有程序共享的堆上。这是一个有限的资源,当该堆存储空间不足时,该堆很小并且程序开始失败。
答案 1 :(得分:3)
您必须启用ResizeRedraw
。将以下内容添加到构造函数中。
this.SetStyle(ControlStyles.ResizeRedraw, true);
答案 2 :(得分:0)
在表单Resize
上粘贴此事件;
this.Refresh();
这将重绘表单并触发Form1.Paint事件。
答案 3 :(得分:0)
之所以发生这种情况,是因为只有部分表单区域在大小更改时才会失效。您需要做的是处理SizeChanged事件并调用表单的刷新方法。
答案 4 :(得分:0)
在绘制之前调用Graphics.Clear();
以清除旧图形并避免创建冗余画笔。在块外部创建画笔的代码
SolidBrush myBrush = new SolidBrush(Color.Black);
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear();
e.Graphics.FillEllipse(myBrush, 0, 0, this.ClientSize.Width, this.ClientSize.Height);
}