gpt4 book ai didi

c# - 使用 CreateGraphics 而不是自定义绘图的 Paint 事件处理程序时出现绘图故障

转载 作者:太空狗 更新时间:2023-10-29 21:12:33 25 4
gpt4 key购买 nike

我编写了一个 Windows 窗体应用程序,我在其中使用 Control.CreateGraphics()Panel 上自定义绘图。这是我的 Form 在启动时的样子:

blank form with Draw! button

自定义绘图是在“Draw!”的 Click 事件处理程序中的顶部面板上执行的。按钮。这是我的按钮点击处理程序:

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 后,表单如下所示:

form with green filled ellipse

成功!

但是当我通过拖动一个角来缩小表格时...

same form, shrunk to partially hide ellipse

...并将其扩展回原来的大小,

form with missing graphics on right and bottom

我画的一部分不见了!

当我将窗口的一部分拖到屏幕外时也会发生这种情况...

form partially offscreen

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

form back onscreen but with half of graphics missing

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

blank form like first image

这是什么原因造成的?我怎样才能使我绘制的图形持久化?

注意:我创建了这个 self 回答的问题,所以我有一个规范的 Q/A 来指导用户,因为这是一个常见的场景,如果您还不知道问题的原因,则很难搜索.

最佳答案

长话短说:

不要使用 Control.CreateGraphics 响应一次性 UI 事件进行绘图。相反,为要在其上绘画的控件注册一个 Paint 事件处理程序,并使用通过 PaintEventArgs 传递的 Graphics 对象进行绘图.

如果您只想在单击按钮后绘制(例如),请在您的 Click 处理程序中设置一个 bool 标志,指示该按钮已被单击,然后调用 Control.Invalidate ()。然后在 Paint 处理程序中有条件地进行渲染。

最后,如果您的控件的内容应该随着控件的大小而改变,请注册一个 Resize 事件处理程序并在那里调用 Invalidate()。

示例代码:

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();
}

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

看看 documentation for Control.CreateGraphics :

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 不负责保留您在 Control 中绘制的图形。相反,它会识别您的控件需要重新绘制的情况,并使用 WM_PAINT 消息通知它。然后由您自己控制重新绘制。这发生在 OnPaint 方法中,如果您对 Control 或其子类之一进行子类化,则可以重写该方法。如果您没有子类化,您仍然可以通过处理公共(public) Paint 事件来进行自定义绘图,控件将在其 OnPaint 方法快结束时触发该事件。这是您要 Hook 的地方,以确保每次 Control 被告知重新绘制时都会重新绘制图形。否则,部分或全部控件将被绘制为控件的默认外观。

重绘发生在控件的全部或部分无效时。您可以通过调用 Control.Invalidate() 使整个控件无效,请求完全重绘。其他情况可能只需要部分重绘。如果 Windows 确定只有 Control 的一部分需要重新绘制,则您收到的 PaintEventArgs 将具有非空的 ClipRegion。在这种情况下,您的绘制只会影响 ClipRegion 中的区域,即使您尝试绘制到该区域之外的区域也是如此。这就是上例中需要调用 drawPanel.Invalidate() 的原因。因为 drawPanel 的外观需要随着控件的大小而改变,并且当窗口展开时只有控件的新部分无效,所以每次调整大小都需要请求完全重绘。

关于c# - 使用 CreateGraphics 而不是自定义绘图的 Paint 事件处理程序时出现绘图故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30419493/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com