我可以在“绘制”事件之外的任何其他事件中使用Graphics对象吗

本文关键字:事件 其他 对象 Graphics 任何 绘制 我可以 | 更新日期: 2023-09-27 18:22:17

我有一个带有停靠面板的WinForm。我否决了Panel的Paint事件。我有一行设置图形对象(_G):

private Graphics _graphics;

在覆盖中,我初始化图形对象(_G):

private void GridPanel_Paint(object sender, PaintEventArgs e)
{
    _graphics = e.Graphics;
    <snip>
    …
    </snip>
}

愚蠢的部分来了,我可以在像MouseMove这样的任何其他事件中使用这个_graphics对象吗?

我可以在“绘制”事件之外的任何其他事件中使用Graphics对象吗

这取决于你所说的"使用"是什么意思。

Graphics是一次性的。重新绘制后,控件将处理传递给Paint事件处理程序的Graphics实例。从这一点来看,已处理的对象是无用的。但是缓存对该实例的引用是绝对合法的。

是的,您可以在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...;
    }
}

票据

  1. 调用OnPaint/Paint后,e。图形将被释放,因此,设置对该对象的全局引用将是无用的,因为一旦绘制事件完成,它将是null
  2. 如果在Paint/PaintBackground方法/事件之外绝对需要Graphics,则可以使用CreateGraphics(),但不建议这样做
  3. Paint/PaintBackground自然地属于WinForms事件/呈现管道,因此理想情况下应该覆盖它们并适当地使用它们

如果您想在MouseMove事件上重新绘制面板,请调用Invalidate()方法并在Paint事件上执行绘制逻辑。

Invalidate()方法将面板标记为"脏",并且绘画将由winforms消息循环引起。

您可以使用CreateGraphics方法在需要的地方使用控件的图形对象,当控件刷新时,您的绘画将消失。

因此Paint事件中,最好根据某些逻辑绘制您需要的内容,然后每次刷新控件时,您的绘制逻辑都会应用,并且绘图将显示在控件上。

例如当您想在MouseMove事件中绘制矩形时,只需将矩形存储在类成员变量中,然后调用yourControl.Invalidate();,然后在Paint事件处理程序中使用矩形并绘制即可。Invalidate会重新绘制控件,因此绘制逻辑将运行。