为什么PaintEventArgs.图形的行为与Control.CreateGraphics不同

本文关键字:Control CreateGraphics 不同 PaintEventArgs 图形 为什么 | 更新日期: 2023-09-27 18:15:40

我已经编写了一个事件处理程序方法,并将其附加到FormPaint事件(只是主窗口)。这个事件发送一个包含Graphics属性的PaintEventArgs,它是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实例,如果窗体不需要重新绘制;还有什么是我错过的吗?

为什么PaintEventArgs.图形的行为与Control.CreateGraphics不同

你们这些. net WinForms孩子真的应该学习Win32 API。快去买一本佩佐德的书!

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

假设g2是对从BeginPaint接收到的设备上下文的包装器。我想WinForms会为你包装PAINTSTRUCT::rcPaint——这个变量描述了要绘制的区域。这是预期的行为-而不是消耗CPU周期重新绘制你的整个窗口,每次另一个窗口重叠它只是一个像素,你可以重新绘制…只有一个像素!

g2.Clear可能受到rcPaint的限制。

g1可能是窗口的GetDC -它给了你整个表面来绘制。

为什么,无论是图形对象,是图像只有重新绘制时,窗口的大小增加,而不是当它变小?

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

如果PaintEventArgs

。图形可以(或不应该)用于绘图,它的用途是什么?我想它只是防止你不得不创建一个新的图形实例,如果窗体不需要重新绘制;还有什么是我错过的吗?

是用来画画的。除非你有一些复杂的绘图要求,你可以使用PaintEventArgs.Graphics最小化你的窗口上的绘画量。(如上所述-这是一个巨大的CPU周期节省器,它可能是BeginPaintEndPaint的简单包装-这就是如何绘制到客户端区域。)

  1. 为什么g1在整个窗口中重新绘制图像,而g2只绘制新部分,即使我在绘制之前调用g2. clear () ?
    我不明白这一点,你在两种情况下都画得很完整。所以两者都应该绘制整个表单,也许你在不同的代码中有这种行为

  2. 为什么,无论是图形对象,是图像只有重新绘制时,窗口的大小增加,而不是当它变小?
    因为你应该在Form中调用Invalidate()。调整大小事件以启动重绘

  3. 如果PaintEventArgs
  4. 。图形可以(或不应该)用于绘图,它的用途是什么?我想它只是防止你不得不创建一个新的图形实例,如果窗体不需要重新绘制;还有什么是我错过的吗?
    它们是不同的,CreateGraphics是一个临时对象,应该在使用后立即处理(或在using块中使用),它用于不需要绘图的简单任务,例如MeasureString或获取上下文信息。对于绘图,你总是应该使用PaintEventArgs.Graphics。当使用双缓冲时,差异将是明显的,如果你使用CreateGraphics获得图形对象,你将获得控件的图形对象,而从PaintEventArgs获得它将获得缓冲位图。