首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有效使用OnPaint

有效使用OnPaint
EN

Stack Overflow用户
提问于 2009-12-18 04:28:37
回答 5查看 3K关注 0票数 2

我正在使用C#在Visual Studio .Net中编程。

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

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

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

最重要的是,我有一个功能,可以让你放大和平移海浪,以获得更好的视图(行为很像谷歌地图),所有9个海浪放大和平移在一起。

所有这些功能都是非常“不稳定”的,因为我在mousemove和mousemove上调用了invalidate。基本上,这一切都可以工作,但并不像我想的那样顺利。

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

任何帮助我都会非常感激,即使它只是给我指明了正确的方向。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-12-18 04:31:47

创建一个Bitmap对象,并绘制到该对象。

在你的画图处理程序中,只需将位图blit到屏幕上。

这将允许您从重新渲染数据中解耦更改比例。

票数 7
EN

Stack Overflow用户

发布于 2009-12-18 04:30:36

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

我的DoubleBufferedGraphics类:

代码语言:javascript
复制
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中使用它

代码语言:javascript
复制
protected override void OnPaint(PaintEventArgs e)
{
    if (!_DoubleBufferedGraphics.Initialized)
    {
        _DoubleBufferedGraphics.Initialize(Width, Height);
    }

    _DoubleBufferedGraphics.Graphics.DrawLine(...);

    _DoubleBufferedGraphics.Render(e.Graphics);
}

ControlStyles如果我使用它,我通常会设置它(您可能有不同的需求):

代码语言:javascript
复制
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);

编辑:

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

票数 3
EN

Stack Overflow用户

发布于 2009-12-18 05:00:56

我有两点要补充:

  1. 你说你有8192分。您的绘图区域可能不超过1000个。我想你可以通过每隔10行左右添加一条线来“降低分辨率”。
  2. 你可以使用GraphicsPath类来存储所有需要的线,然后用Graphics.DrawPath

一次性绘制它们

这样,您将避免使用静态位图(以允许缩放),同时仍能获得一些性能改进。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1924345

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档