当ClientSize发生变化时,GDI +绘图会被破坏

时间:2014-02-26 10:41:23

标签: c# winforms gdi+

我需要绘制一个整个表单大小的圆圈。我使用以下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上找不到合适的主题。

5 个答案:

答案 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);
}