我可以在除 Paint 事件之外的任何其他事件中使用 Graphics 对象吗?
Can I use Graphics object in any other event than Paint event?
我有一个带有停靠面板的 WinForm。
我覆盖了 Panel 的 Paint 事件。
我有一行设置 _graphics 对象:
private Graphics _graphics;
在覆盖中我初始化了 _graphics 对象:
private void GridPanel_Paint(object sender, PaintEventArgs e)
{
_graphics = e.Graphics;
<snip>
…
</snip>
}
愚蠢的部分来了,我可以在 MouseMove 等任何其他事件中使用这个 _graphics 对象吗?
这取决于你所说的"use"是什么意思。
Graphics
是一次性的。重新绘制后,控件会处理 Graphics
实例,该实例已传递到 Paint
事件处理程序。从那时起,处置的对象是无用的。但是缓存对该实例的引用是绝对合法的。
您可以在需要的地方使用 CreateGraphics
方法使用控件的图形对象,但是当控件刷新时,您的绘图将消失。
所以最好根据一些逻辑在Paint
事件中绘制你需要的东西,然后每次控件刷新时,你的绘制逻辑将应用并且绘图将显示在您的控件上。
例如当你想在你的MouseMove
事件中绘制一个矩形时,将矩形存储在class成员变量中就足够了,并且调用 yourControl.Invalidate();
然后使用 Paint
事件处理程序中的矩形并绘制它。 Invalidate
使控件重绘,因此您的绘画逻辑将 运行。
是的,您可以在 Paint/PaintBackground
事件之外使用 Graphics,但您不需要,也不建议这样做。
我的猜测是(假定您引用了 MouseMove
)您希望在控件上发生特定事件时进行一些绘制;有几个解决方案:
- 子类化(更好地控制您的组件、控制重用等)
- 正在注册事件处理程序(有利于快速和肮脏的实施)
示例 1 - 注册事件处理程序
private void panel1_MouseMove(object sender, EventArgs e)
{
// forces paint event to fire for entire control surface
panel1.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.....;
}
示例 2 - 子类化
class CustomControl : Control
{
public CustomControl()
{
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
}
protected override void OnMouseMove(EventArgs e)
{
base.OnMouseMove(e);
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics...;
}
}
注释
- 一旦
OnPaint/Paint
被调用,e.Graphics 将被释放,因此,设置对该对象的全局引用将毫无用处,因为一旦您的 Paint 事件发生,它将成为 null
完成。
- 如果您在
Paint/PaintBackground
methods/events 之外绝对需要 Graphics
,则可以使用 CreateGraphics()
,但不建议这样做。
Paint/PaintBackground
自然地落入 WinForms event/rendering 管道,因此您最好覆盖这些并适当地使用它们。
如果您想在 MouseMove 事件上重绘面板,请调用 Invalidate()
方法并在 Paint
事件上执行绘制逻辑。
Invalidate()
方法标记面板"dirty",绘画将由winforms消息循环引起。
我有一个带有停靠面板的 WinForm。 我覆盖了 Panel 的 Paint 事件。 我有一行设置 _graphics 对象:
private Graphics _graphics;
在覆盖中我初始化了 _graphics 对象:
private void GridPanel_Paint(object sender, PaintEventArgs e)
{
_graphics = e.Graphics;
<snip>
…
</snip>
}
愚蠢的部分来了,我可以在 MouseMove 等任何其他事件中使用这个 _graphics 对象吗?
这取决于你所说的"use"是什么意思。
Graphics
是一次性的。重新绘制后,控件会处理 Graphics
实例,该实例已传递到 Paint
事件处理程序。从那时起,处置的对象是无用的。但是缓存对该实例的引用是绝对合法的。
您可以在需要的地方使用 CreateGraphics
方法使用控件的图形对象,但是当控件刷新时,您的绘图将消失。
所以最好根据一些逻辑在Paint
事件中绘制你需要的东西,然后每次控件刷新时,你的绘制逻辑将应用并且绘图将显示在您的控件上。
例如当你想在你的MouseMove
事件中绘制一个矩形时,将矩形存储在class成员变量中就足够了,并且调用 yourControl.Invalidate();
然后使用 Paint
事件处理程序中的矩形并绘制它。 Invalidate
使控件重绘,因此您的绘画逻辑将 运行。
是的,您可以在 Paint/PaintBackground
事件之外使用 Graphics,但您不需要,也不建议这样做。
我的猜测是(假定您引用了 MouseMove
)您希望在控件上发生特定事件时进行一些绘制;有几个解决方案:
- 子类化(更好地控制您的组件、控制重用等)
- 正在注册事件处理程序(有利于快速和肮脏的实施)
示例 1 - 注册事件处理程序
private void panel1_MouseMove(object sender, EventArgs e)
{
// forces paint event to fire for entire control surface
panel1.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.....;
}
示例 2 - 子类化
class CustomControl : Control
{
public CustomControl()
{
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
}
protected override void OnMouseMove(EventArgs e)
{
base.OnMouseMove(e);
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics...;
}
}
注释
- 一旦
OnPaint/Paint
被调用,e.Graphics 将被释放,因此,设置对该对象的全局引用将毫无用处,因为一旦您的 Paint 事件发生,它将成为null
完成。 - 如果您在
Paint/PaintBackground
methods/events 之外绝对需要Graphics
,则可以使用CreateGraphics()
,但不建议这样做。 Paint/PaintBackground
自然地落入 WinForms event/rendering 管道,因此您最好覆盖这些并适当地使用它们。
如果您想在 MouseMove 事件上重绘面板,请调用 Invalidate()
方法并在 Paint
事件上执行绘制逻辑。
Invalidate()
方法标记面板"dirty",绘画将由winforms消息循环引起。