C#.NET .. 在 Paint 事件处理程序之外绘制是一种不好的做法吗?
C#.NET .. is it a bad practice to draw outside the Paint event handler?
为了澄清我的问题的意思。我在使用 .NET 框架在 C# 中制作游戏时习惯于实现我自己的 DrawScene() 方法并在我想重绘游戏图形时调用它(基本上在游戏中的任何实例移动或更改其 shape/state 之后,如下所示:
private void DrawScene()
{
Graphics g = this.CreateGraphics();
g.Clear(Color.Black);
g.DrawImage(myBitmap, 0, 0);
g.Dispose();
}
这样做,在我的 Paint 事件处理程序中,我所做的就是以下操作:
private void Form1_Paint(object sender, PaintEventArgs e)
{
DrawScene();
}
例如,当我想在玩家移动后重绘时,我只需以相同的方式调用 DrawScene():
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Keycode == Keys.Up)
{
hero.y -= 5;
}
DrawScene();
}
这样做和这样做有什么严重的区别吗(我注意到大多数人都遵循):
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Black);
e.Graphics.DrawImage(myBitmap, 0, 0);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Keycode == Keys.Up)
{
hero.y -= 5;
}
this.Invalidate();
}
对不起,如果说的太多了,但我只是想澄清一下我的问题..
因此,如果上述两种情况的绘图方式完全相同(从图形的角度来看),并且像第一种情况那样保持我通常的实现方式也没有什么坏处。那么什么时候最好使用invalidate() 方法?
这两种方法差别很大(首选第二种)。
首先 - 在您的方法中,您每次需要绘制某些东西时都会创建新的 Graphics
对象,而在 Paint
事件处理程序中,您每次都使用相同的图形对象。
这会增加内存使用量(因为重绘会非常频繁地发生),而且因为您没有处理正在创建的图形(基本上您应该对任何实现了 IDisposable
的对象执行此操作,您不再需要使用) - 图形使用的系统资源未被释放。
此外,您的表单可以通过调用手动重绘,但在某些其他情况下(与其他 window、show/hide 等重叠)。如果您的绘画将在 Paint
处理程序中完成 - 那么它们将自动完成,但在您的 "first" 方法中,除非您手动调用绘图方法,否则它们不会自动完成。
所以基本上最好在 Paint
事件处理程序中绘制所有内容(并调用 Invalidate
甚至 Refresh
强制重绘)而不是在单独的方法中手动绘制。
有时(如果您的绘图需要很多代码并且可以在逻辑上分成几部分)最好像这样处理它:
private void DrawScene(Graphics g)
{
g.Clear(Color.Black);
g.DrawImage(myBitmap, 0, 0);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DrawScene(e.Graphics);
DrawSomething(e.Graphics);
}
所以您仍然使用 Paint 事件处理程序中的图形对象,但只是将其传递给绘图方法。
为了澄清我的问题的意思。我在使用 .NET 框架在 C# 中制作游戏时习惯于实现我自己的 DrawScene() 方法并在我想重绘游戏图形时调用它(基本上在游戏中的任何实例移动或更改其 shape/state 之后,如下所示:
private void DrawScene()
{
Graphics g = this.CreateGraphics();
g.Clear(Color.Black);
g.DrawImage(myBitmap, 0, 0);
g.Dispose();
}
这样做,在我的 Paint 事件处理程序中,我所做的就是以下操作:
private void Form1_Paint(object sender, PaintEventArgs e)
{
DrawScene();
}
例如,当我想在玩家移动后重绘时,我只需以相同的方式调用 DrawScene():
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Keycode == Keys.Up)
{
hero.y -= 5;
}
DrawScene();
}
这样做和这样做有什么严重的区别吗(我注意到大多数人都遵循):
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Black);
e.Graphics.DrawImage(myBitmap, 0, 0);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Keycode == Keys.Up)
{
hero.y -= 5;
}
this.Invalidate();
}
对不起,如果说的太多了,但我只是想澄清一下我的问题..
因此,如果上述两种情况的绘图方式完全相同(从图形的角度来看),并且像第一种情况那样保持我通常的实现方式也没有什么坏处。那么什么时候最好使用invalidate() 方法?
这两种方法差别很大(首选第二种)。
首先 - 在您的方法中,您每次需要绘制某些东西时都会创建新的 Graphics
对象,而在 Paint
事件处理程序中,您每次都使用相同的图形对象。
这会增加内存使用量(因为重绘会非常频繁地发生),而且因为您没有处理正在创建的图形(基本上您应该对任何实现了 IDisposable
的对象执行此操作,您不再需要使用) - 图形使用的系统资源未被释放。
此外,您的表单可以通过调用手动重绘,但在某些其他情况下(与其他 window、show/hide 等重叠)。如果您的绘画将在 Paint
处理程序中完成 - 那么它们将自动完成,但在您的 "first" 方法中,除非您手动调用绘图方法,否则它们不会自动完成。
所以基本上最好在 Paint
事件处理程序中绘制所有内容(并调用 Invalidate
甚至 Refresh
强制重绘)而不是在单独的方法中手动绘制。
有时(如果您的绘图需要很多代码并且可以在逻辑上分成几部分)最好像这样处理它:
private void DrawScene(Graphics g)
{
g.Clear(Color.Black);
g.DrawImage(myBitmap, 0, 0);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DrawScene(e.Graphics);
DrawSomething(e.Graphics);
}
所以您仍然使用 Paint 事件处理程序中的图形对象,但只是将其传递给绘图方法。