【问题标题】:How can I draw the current Graphics object without clear?如何在不清除的情况下绘制当前的 Graphics 对象?
【发布时间】:2016-04-04 14:55:45
【问题描述】:

我想使用点列表绘制函数图形。但是当存在这么多点时,它正在放慢速度。所以我认为如果我可以在不擦除当前绘图的情况下进行绘图,我就不需要存储这些点。我知道Invalidate 清除当前绘图。我该怎么做?

我目前正在使用这种方法:

    CoordinateSystem cos = new CoordinateSystem();
    List<PointF> points = new List<PointF>();
    float a = -20;
    void Form1_Tick(object sender, EventArgs e)
    {
        panel1.Invalidate();
    }
    void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        double x = a;
        double y = Root(x, 3);
        cos.DrawSystem(e.Graphics);
        points.Add(cos.RelativePoint(new PointF((float)x, (float)y)));
        for (int i = 1; i < points.Count - 1; i++)
        {
         e.Graphics.DrawLine(Pens.Red,points[i],points[i+1]);
        }
        a += 0.05f;

    }

更新

正如你所建议的,我使用了位图来重绘。但是结果的质量对我来说并不好。此外,我不知道如何仅在数据更改时调用Invalidate。因为这里,当Invalidate方法被调用时,数据会发生变化。

代码:

CoordinateSystem cos = new CoordinateSystem();
    Bitmap bmp;
    float a = -20;
    void Form1_Tick(object sender, EventArgs e)
    {
        panel1.Invalidate();
    }

    void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        double x = a;
        double y = Root(x, 3);
        PointF rel = cos.RelativePoint(new PointF((float)x, (float)y));
        using (Graphics grp = Graphics.FromImage(bmp))
        {
            grp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            cos.DrawSystem(grp);
            grp.DrawEllipse(Pens.Red, rel.X - 0.5f, rel.Y - 0.5f, 1, 1);
        }
        e.Graphics.DrawImage(bmp, 0, 0);
        a += 0.01f;
    }

正如您在结果中看到的,数字文本质量不佳:

更新 2: 好的,我稍微更改了代码。只需在Load 事件中绘制一次坐标系,它现在就具有良好的质量。感谢大家的帮助!

【问题讨论】:

  • 您似乎从 Timer 滴答声中调用了 Invalidate()?为什么要这么做。当数据发生变化时,只需要调用 Invalidate 触发表单重绘即可。
  • 绘制位图,然后在您的绘制事件中执行 DrawImage。您的计时器事件似乎没有必要。如何更新正在使用的图形变量?
  • 是的,绘制到缓冲区图像,然后绘制到您的控件。并且不要将 invalidate 放在 tick 事件处理程序中。
  • 只更新tick事件中的变量和位图。绘制事件不应该更新变量,它应该只绘制。看起来你每次都在自己上面绘制坐标系——只画一次。
  • Graphics 对象不包含任何图形;它是一个工具,可让您绘制到相关位图上,包括控件的表面。

标签: c# winforms paint coordinate-systems


【解决方案1】:

没有办法“不清楚”图形。当需要绘制Control(已失效)时,您必须重新绘制所有内容。

稍微改进代码的一种方法是使用Graphics.DrawLines(),而不是遍历这些点并为每个单独的行调用Graphics.DrawLine()

void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    double x = a;
    double y = Root(x, 3);
    cos.DrawSystem(e.Graphics);
    points.Add(cos.RelativePoint(new PointF((float)x, (float)y)));
    e.Graphics.DrawLines(Pens.Red, points.ToArray());
}

【讨论】:

    【解决方案2】:

    Paint 事件有一个e.ClipRectangle 属性。

    这是需要重新绘制的实际矩形,因为并不总是需要重新绘制所有内容(例如,表单的一部分移到您的表单上并再次移开)。

    所以你可以做的一件事就是只画出该矩形内的线条。

    但话虽如此,如果您调用 Invalidate,则表明需要重绘整个内容。

    最好跟踪一下你画了哪些,然后只画新的?

    【讨论】:

    • 值得注意的是,Invalidate 的重载将需要重绘的区域作为参数。
    猜你喜欢
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 2021-08-11
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    相关资源
    最近更新 更多