使用的createGraphics而不是Paint事件处理程序,自定义绘制图纸时,故障 [英] Drawing glitches when using CreateGraphics rather than Paint event handler for custom drawing

查看:1683
本文介绍了使用的createGraphics而不是Paint事件处理程序,自定义绘制图纸时,故障的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个Windows窗体应用程序在那里我自上面板使用 Control.CreateGraphics图()。下面是我的表格看起来像在启动:

I've written a Windows Forms app where I do custom drawing on a Panel using Control.CreateGraphics(). Here's what my Form looks like at startup:

自定义绘图中的的点击事件处理程序的顶部面板上进行画!按钮。这里是我的按钮单击处理程序:

The custom drawing is performed on the top panel in the Click event handler of the "Draw!" button. Here's my button click handler:

private void drawButton_Click(object sender, EventArgs e)
{
    using (Graphics g = drawPanel.CreateGraphics())
    {
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.Clear(Color.White);
        Size size = drawPanel.ClientSize;
        Rectangle bounds = drawPanel.ClientRectangle;
        bounds.Inflate(-10, -10);
        g.FillEllipse(Brushes.LightGreen, bounds);
        g.DrawEllipse(Pens.Black, bounds);
    }
}

drawButton 点击后,形式如下:

成功!

但是当我通过拖动一个角落缩的形式...

But when I shrink the form by dragging a corner...

...并展开它恢复到原来的大小,

...and expand it back to its original size,

什么,我画了就没了一部分!

part of what I drew is gone!

这也发生在我拖动窗口的一部分屏幕外...

This also happens when I drag part of the window offscreen...

...并将其拖回屏幕上:

...and drag it back onscreen:

如果我最小化窗口,恢复它,整个图像被删除:

If I minimize the window and restore it, the whole image is erased:

是什么原因造成的?我怎样才能使它所以我画的图形是执着?

What is causing this? How can I make it so the graphics I draw are persistent?

请注意:我创建这个自我回答问题,所以我有一个规范的Q / A直接用户,因为这是一个常见的​​场景,很难搜索,如果你不已经知道了问题的原因

Note: I've created this self-answered question so I have a canonical Q/A to direct users to, as this is a common scenario that's hard to search for if you don't already know the cause of the problem.

推荐答案

不要做您的绘图响应一次性UI事件与 Control.CreateGraphics 。相反,注册一个油漆事件处理程序,要在其上作画,并与你的绘图控制在图形通过传递的对象的 PaintEventArgs的

TL;DR:

Don't do your drawing in response to a one-time UI event with Control.CreateGraphics. Instead, register a Paint event handler for the control on which you want to paint, and do your drawing with the Graphics object passed via the PaintEventArgs.

如果您希望只点击一个按钮(例如)后作画,在你的点击处理程序中,设置一个布尔值标志,指示按钮被点击,然后调用 Control.Invalidate()。然后做你的渲染条件的油漆处理程序。

If you want to paint only after a button click (for example), in your Click handler, set a boolean flag indicating that the button has been clicked and then call Control.Invalidate(). Then do your rendering conditionally in the Paint handler.

最后,如果你的控件的内容应与控件的大小发生变化,注册调整事件处理程序并调用invalidate()也有。

Finally, if your control's contents should change with the size of the control, register a Resize event handler and call Invalidate() there too.

举例code:

private bool _doCustomDrawing = false;

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
    if (_doCustomDrawing)
    {
        Graphics g = e.Graphics;
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.Clear(Color.White);
        Size size = drawPanel.ClientSize;
        Rectangle bounds = drawPanel.ClientRectangle;
        bounds.Inflate(-10, -10);
        g.FillEllipse(Brushes.LightGreen, bounds);
        g.DrawEllipse(Pens.Black, bounds);
    }
}

private void drawButton_Click(object sender, EventArgs e)
{
    _doCustomDrawing = true;
    drawPanel.Invalidate();
}

private void drawPanel_Resize(object sender, EventArgs e)
{
    drawPanel.Invalidate();
}

但是,为什么?什么是我做错了,这又如何解决?

看看的<一个href=\"https://msdn.microsoft.com/en-us/library/system.windows.forms.control.creategraphics%28v=vs.110%29.aspx\">documentation为Control.CreateGraphics 的:

Graphics对象,你通过的createGraphics方法通常不应当前的Windows消息已经被处理后予以保留检索,因为任何画着该对象将与下一个WM_PAINT消息被删除。

The Graphics object that you retrieve through the CreateGraphics method should not normally be retained after the current Windows message has been processed, because anything painted with that object will be erased with the next WM_PAINT message.

Windows不承担责任,保持你画你的控制图形。相反,它标识了您的控制将需要重新绘制的情况下,用WM_PAINT消息通知它。然后,就看你的控制重绘自己。这发生在的OnPaint 方法,如果你继承它的子类控制或一个你可以重写。如果你没有继承,你仍可以通过定制处理公共油漆事件,控制将触发其附近的OnPaint年底绘图方法。这是你要挂钩的,以确保您的图形得到重绘每次控制被告知要重新绘制的时间。否则,部分或全部控件将被涂到控件的默认外观。

Windows doesn't take responsibility for retaining the graphics you draw to your Control. Rather, it identifies situations in which your control will require a repaint and informs it with a WM_PAINT message. Then it's up to your control to repaint itself. This happens in the OnPaint method, which you can override if you subclass Control or one of its subclasses. If you're not subclassing, you can still do custom drawing by handling the public Paint event, which a control will fire near the end of its OnPaint method. This is where you want to hook in, to make sure your graphics get redrawn every time the Control is told to repaint. Otherwise, part or all of your control will be painted over to the control's default appearance.

重新油漆时发生的所有或控制的部分的无效的。您可以无效整个控件,要求一个完整的重绘,通过调用 Control.Invalidate()。其他情况下可能需要仅仅一个局部重绘。如果Windows确定,只有控制的一部分需要重新绘制,在 PaintEventArgs的您收到将有一个非空 Cli时pregion 。在这种情况下,您的绘图只会影响在 Cli时pregion 的区域,即使你尝试绘制到该区域以外的地区。这就是为什么()在上面的例子中所需要的呼叫到 drawPanel.Invalidate。由于外观 drawPanel 需要与控件的大小,并改变只有当扩大了窗口控件的新的部分无效,有必要请求完全重绘每次调整大小。

Repainting happens when all or part of a control is invalidated. You can invalidate the entire control, requesting a full repaint, by calling Control.Invalidate(). Other situations may require only a partial repaint. If Windows determines that only part of a Control needs to be repainted, the PaintEventArgs you receive will have a non-empty ClipRegion. In this situation, your drawing will only affect the area in the ClipRegion, even if you try to draw to areas outside that region. This is why the call to drawPanel.Invalidate() was required in the above example. Because the appearance of drawPanel needs to change with the size of the control and only the new parts of the control are invalidated when the window is expanded, it's necessary to request a full repaint with each resize.

这篇关于使用的createGraphics而不是Paint事件处理程序,自定义绘制图纸时,故障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆