0

我编写了一个事件处理程序方法并将其附加到Painta 的事件Form(只是主窗口)。此事件发送一个PaintEventArgs包含一个名为 的属性Graphics,它是 的一个实例System.Drawing.Graphics

这是我正在使用的代码:

private void Form1_Paint(object sender, PaintEventArgs e) {

    Bitmap bm = new Bitmap("fruit-dealer-full.jpg");

    Graphics g1 = this.CreateGraphics();
    Graphics g2 = e.Graphics;

    // g1.DrawImage(bm, 0, 0, this.Width, this.Height);
    // g1.DrawRectangle(
    //       Pens.White, 10.0f, 10.0f, this.Width - 200, this.Height - 200);

    g2.DrawImage(bm, 0, 0, this.Width, this.Height);
    g2.DrawRectangle(
           Pens.White, 10.0f, 10.0f, this.Width - 200, this.Height - 200);

}

最终,我只是想更好地了解这里发生的事情,但具体来说,我有以下三个问题:

  1. 为什么g1在整个窗口中重绘图像,而g2只绘制新部分,即使我g2.Clear()在绘制之前调用?
  2. 为什么对于任Graphics一对象,图像仅在窗口增大时才重绘,而不是在窗口变小时时重绘?
  3. 如果PaintEventArgs.Graphics可以(或不应该)用于绘图,它的用途是什么?我想Graphics如果不需要重绘表单,它只会阻止您创建新实例;还有更多我想念的吗?
4

2 回答 2

3

.NET WinForms 孩子真的应该学习 Win32 API。已经拿起了 Petzold 的副本!

为什么 g1 在整个窗口中重绘图像,而 g2 只绘制新部分,即使我在绘制之前调用 g2.Clear() ?

大概g2是从接收到的设备上下文的包装器BeginPaint。我想 WinFormsPAINTSTRUCT::rcPaint会为你包装——这个变量描述了要绘制的区域。这是预期的行为——而不是每次另一个窗口与它重叠一个像素时,每次都重绘整个窗口,而不是消耗 CPU 周期,您可以重绘......只是一个像素!

g2.Clear大概受限于rcPaint

g1可能是一个GetDC窗口 - 它为您提供了整个表面来绘制。

为什么对于任何一个 Graphics 对象,图像仅在窗口大小增加时才重绘,而不是在窗口变小时才重绘?

CS_HREDRAW底层窗口类可能没有CS_VREDRAW窗口样式。没有这些,默认行为就没有理由要求您在窗口变小时重新绘制窗口:Windows 知道整个窗口的样子,它可以剪掉不需要的部分。这与窗口变大时不同,它不知道在新区域中绘制什么。

如果 PaintEventArgs.Graphics 可以(或不应该)用于绘图,它的用途是什么?我想如果不需要重绘表单,它只会阻止您创建新的 Graphics 实例;还有更多我想念的吗?

它用于绘图。除非您有一些复杂的绘图要求,否则您可以使用PaintEventArgs.Graphics最小化进入窗口的绘画量。(如上 - 这是一个巨大的 CPU 周期节省,它可能是一个简单的包装器BeginPaint-EndPaint这就是绘制到客户区域的目的。)

于 2011-11-26T01:24:40.597 回答
1
  1. 为什么 g1 在整个窗口中重绘图像,而 g2 只绘制新部分,即使我在绘制之前调用 g2.Clear() ?
    我无法理解这一点,您在两种情况下都在绘制完整的表格。所以两者都应该绘制整个表格,也许你在不同的代码中有这种行为

  2. 为什么对于任何一个 Graphics 对象,图像仅在窗口大小增加时才重绘,而不是在窗口变小时才重绘?
    因为您应该在 Form.Resize 事件中调用 Invalidate() 来启动重绘

  3. 如果 PaintEventArgs.Graphics 可以(或不应该)用于绘图,它的用途是什么?我想如果不需要重绘表单,它只会阻止您创建新的 Graphics 实例;还有更多我想念的吗?
    它们是不同的,CreateGraphics 是一个临时对象,使用后应该立即释放(或在 using 块内使用),它用于不需要绘制的简单任务,例如 MeasureString 或获取 Context 信息。对于绘图,您始终应该使用 PaintEventArgs.Graphics。使用双缓冲时,差异会很明显的一个很好的场景是,如果使用 CreateGraphics 获取 Graphics 对象,则将获取控件的 Graphics 对象,而从 PaintEventArgs 获取它将获取缓冲位图。
于 2011-11-26T01:10:13.137 回答