Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# OnPaint的高效使用_C#_.net_Graphics_Onpaint - Fatal编程技术网

C# OnPaint的高效使用

C# OnPaint的高效使用,c#,.net,graphics,onpaint,C#,.net,Graphics,Onpaint,我在Visual Studio.Net中编程,并使用C# 我正在创建自己的控件,该控件根据从模数转换器(ADC)获得的值绘制波形。我获取输入点并将其转换为X和Y点,以便在我的控件中正确绘制图形 我的OnPaint方法中有一个循环,它遍历所有点,并在当前点和下一点之间调用DrawLine方法 然而,这是非常低效的,因为其中一些图表有8192个点,而系统实际上有九个ADC,我想同时显示它们。每次重新绘制页面时,所有图形都要花费几乎一秒钟的时间重新绘制(特别是在调试期间) 除此之外,我还提供了一些功能

我在Visual Studio.Net中编程,并使用C#

我正在创建自己的控件,该控件根据从模数转换器(ADC)获得的值绘制波形。我获取输入点并将其转换为X和Y点,以便在我的控件中正确绘制图形

我的OnPaint方法中有一个循环,它遍历所有点,并在当前点和下一点之间调用DrawLine方法

然而,这是非常低效的,因为其中一些图表有8192个点,而系统实际上有九个ADC,我想同时显示它们。每次重新绘制页面时,所有图形都要花费几乎一秒钟的时间重新绘制(特别是在调试期间)

除此之外,我还提供了一些功能,允许您放大和平移波浪以获得更好的视图(就像谷歌地图一样),并且所有9个波浪都可以一起放大和平移

所有这些功能都非常“急促”,因为我在mousewheel和mousemove上调用invalidate。基本上,这一切工作,但不是顺利,因为我想

我想知道是否有一种方法可以从数据中创建一个预先绘制的对象,然后在绘图区域中绘制图片的放大和翻译版本


任何帮助都将不胜感激,即使它只是为我指明了正确的方向。

您可以在控件/窗体上将
双缓冲
设置为true。或者,您可以尝试使用自己的图像创建双缓冲效果

我的
DoubleBufferedGraphics
课程:

public class DoubleBufferedGraphics : IDisposable
{
    #region Constructor
    public DoubleBufferedGraphics() : this(0, 0) { }

    public DoubleBufferedGraphics(int width, int height)
    {
        Height = height;
        Width = width;
    }
    #endregion

    #region Private Fields
    private Image _MemoryBitmap;
    #endregion

    #region Public Properties
    public Graphics Graphics { get; private set; }

    public int Height { get; private set; }

    public bool Initialized
    {
        get { return (_MemoryBitmap != null); }
    }

    public int Width { get; private set; }
    #endregion

    #region Public Methods
    public void Dispose()
    {
        if (_MemoryBitmap != null)
        {
            _MemoryBitmap.Dispose();
            _MemoryBitmap = null;
        }

        if (Graphics != null)
        {
            Graphics.Dispose();
            Graphics = null;
        }
    }

    public void Initialize(int width, int height)
    {
        if (height > 0 && width > 0)
        {
            if ((height != Height) || (width != Width))
            {
                Height = height;
                Width = width;

                Reset();
            }
        }
    }

    public void Render(Graphics graphics)
    {
        if (_MemoryBitmap != null)
        {
            graphics.DrawImage(_MemoryBitmap, _MemoryBitmap.GetRectangle(), 0, 0, Width, Height, GraphicsUnit.Pixel);
        }
    }

    public void Reset()
    {
        if (_MemoryBitmap != null)
        {
            _MemoryBitmap.Dispose();
            _MemoryBitmap = null;
        }

        if (Graphics != null)
        {
            Graphics.Dispose();
            Graphics = null;
        }

        _MemoryBitmap = new Bitmap(Width, Height);
        Graphics = Graphics.FromImage(_MemoryBitmap);
    }

    /// <summary>
    /// This method is the preferred method of drawing a background image.
    /// It is *MUCH* faster than any of the Graphics.DrawImage() methods.
    /// Warning: The memory image and the <see cref="Graphics"/> object
    /// will be reset after calling this method. This should be your first
    /// drawing operation.
    /// </summary>
    /// <param name="image">The image to draw.</param>
    public void SetBackgroundImage(Image image)
    {
        if (_MemoryBitmap != null)
        {
            _MemoryBitmap.Dispose();
            _MemoryBitmap = null;
        }

        if (Graphics != null)
        {
            Graphics.Dispose();
            Graphics = null;
        }

        _MemoryBitmap = image.Clone() as Image;

        if (_MemoryBitmap != null)
        {
            Graphics = Graphics.FromImage(_MemoryBitmap);
        }
    }
    #endregion
}
如果我使用它,通常会设置控制样式(您可能有不同的需求):

编辑:


好的,因为数据是静态的,所以您应该先绘制图像(在OnPaint之前),然后在OnPaint中使用
Graphics.DrawImage()
重载将源图像的正确区域绘制到屏幕上。如果数据不变,则没有理由重新绘制线条。

创建位图对象,并绘制到该对象

在绘制处理程序中,只需将位图点显到屏幕上


这将允许您将更改比例与重新渲染数据分离。

您可以绘制多行。我不确定这在C#中是什么样子,但它必须存在(它是一个基于GDI/GDI+的API)。这允许您一次性指定所有点,并允许Windows稍微优化调用(减少堆栈推送/弹出以留在绘图算法中,而不是为每个新点返回代码)

编辑:但是如果您的数据是静态的,那么使用输出的双缓冲/缓存图像比担心它的初始绘制更有效


这里有一个链接:

我要补充两点:

  • 你说你得了8192分。您的绘图区域可能不超过1000。我想你可以通过每10行左右增加一行来“降低分辨率”
  • 您可以使用GraphicsPath类存储所有必需的线,并使用Graphics.DrawPath一次性绘制所有线

  • 通过这种方式,您将避免使用静态位图(允许缩放),同时仍能获得一些性能改进。

    只需计算可见范围并仅绘制这些点即可。
    使用双缓冲。最后,您可以使用原始位图数据创建自己的多行绘图实现,例如,使用锁位并将像素颜色直接写入构成图片的字节中。使用Invalidate(..)重新绘制窗口的一部分。

    双缓冲并不能加快重绘速度,它只是消除了闪烁。这里需要做的是允许数据平移、缩放等,而无需全部重新渲染。根据OP,随着新数据来自ADC,数据会发生变化,因此静态图像也不是解决方案。双缓冲将解决他所描述的急躁,并能导致更快的绘图。Cory,数据不会流入。对不起,如果我不清楚。10-4,请参阅我的编辑。使用静态图像,只绘制一次,然后只绘制原始图像的一部分,效率应该更高。将消除平移/缩放时(重新)绘制线条所需的时间。请在我的帖子中不清楚的地方发表以下评论。数据没有流入。我请求一组数据,然后使用该数据集,因此静态图像是一种可能的解决方案。我只是想澄清一下。我现在正在研究其他建议。对于平移很好,但这如何与缩放(同时进行文本标记)一起工作。缩放时,可以在背景中以新的缩放级别重新渲染。谷歌地图显示旧视图模糊放大版本的方式,直到它以新的缩放级别在图像中流动。
    protected override void OnPaint(PaintEventArgs e)
    {
        if (!_DoubleBufferedGraphics.Initialized)
        {
            _DoubleBufferedGraphics.Initialize(Width, Height);
        }
    
        _DoubleBufferedGraphics.Graphics.DrawLine(...);
    
        _DoubleBufferedGraphics.Render(e.Graphics);
    }
    
    SetStyle(ControlStyles.UserPaint, true);
    SetStyle(ControlStyles.AllPaintingInWmPaint, true);
    SetStyle(ControlStyles.DoubleBuffer, true);