【问题标题】:Can I use Graphics object in any other event than Paint event?我可以在除 Paint 事件之外的任何其他事件中使用 Graphics 对象吗?
【发布时间】:2015-11-17 14:20:59
【问题描述】:

我有一个带有停靠面板的 WinForm。 我覆盖了 Panel 的 Paint 事件。 我有一行设置 _graphics 对象:

private Graphics _graphics;

在覆盖中我初始化 _graphics 对象:

private void GridPanel_Paint(object sender, PaintEventArgs e)
{
    _graphics = e.Graphics;

    <snip>
    …
    </snip>
}

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

【问题讨论】:

标签: c# winforms gdi+


【解决方案1】:

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

Graphics 是一次性的。重绘后,控件处理Graphics 实例,该实例被传递到Paint 事件处理程序。从那时起,已处置的对象就没有用了。但是缓存对该实例的引用是绝对合法的。

【讨论】:

  • 在 Paint 事件中,我使用灰色笔在 Panel 中绘制了一个网格。在 MouseMove 中,我想用红笔重新绘制鼠标指针当前所在的方格。
  • @Randy:你不需要记住图形。相反,记住要重绘的方形参数并调用Invalidate
  • 仅使用 MouseMove 事件来识别您要更改的单元格,并在该单元格更改时强制重绘控件。然后在 Paint 处理程序中添加您的自定义绘图。
【解决方案2】:

是的,您可以在 Paint/PaintBackground 事件之外使用图形,但您不需要,也不建议这样做。

我的猜测是(假设您引用了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.Graphics 将被释放,因此,设置对该对象的全局引用将毫无用处,因为一旦您的Paint 事件完成,它将是null
  2. 如果您在 Paint/PaintBackground 方法/事件之外绝对需要 Graphics,则可以使用 CreateGraphics(),但不建议这样做。
  3. Paint/PaintBackground 自然而然地属于 WinForms 事件/渲染管道,因此您最好覆盖这些并适当地使用它们。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      你可以在你想要的地方使用CreateGraphics方法使用你的控件的图形对象,但是当控件刷新时,你的绘画会消失。

      所以最好在Paint事件中根据一些逻辑绘制你需要的东西,然后每次控件刷新时,你的绘制逻辑就会应用,并且绘图会显示在你的控件上。

      例如当你想在你的MouseMove事件中绘制一个矩形时,将矩形存储在一个类成员变量中就足够了,然后调用yourControl.Invalidate();然后在Paint 事件处理程序并绘制它。 Invalidate 使控件重绘,因此您的绘画逻辑将运行。

      【讨论】:

      • 很高兴发表评论反对投票的原因并让我知道答案有什么问题。
      • 有人试探性地看到了CreateGraphics 并自动投了反对票。
      • @TaW 以及 CreateGraphics 如何在不阅读其余答案的情况下投反对票。 :-/
      • 没说是这样,只是认为这是一个合理的解释。有些人会找任何理由投反对票..
      • @TaW 感谢您的反馈。
      猜你喜欢
      • 2014-10-07
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多