学海无涯

导航

GDI+性能优化

每个 Windows 控件都可以拥有一个 paint 事件处理程序和一个表示此控件是绘图画布的 Graphics 对象。这意味着我们可以使用一个按钮或一个列表框作为绘图画布。

如果在菜单或按钮的 Click 事件处理程序中绘制图形对象,则必须最后调用 this.Invalidate() 方法。如果不调用,窗体将不会重新绘制自身,但是如果我们在窗体的 OnPaint 或 paint 事件处理程序中编写

一些代码,则不需要使窗体无效。

释放图形对象

如果一个 Graphics 对象是通过 CreateGraphics 方法或其他 CreateFrom 方法创建的,则必须释放此对对象,即手动调用  g.Dispose() 方法 。

如果我们在 paint 事件中或从 PaintEventArgs.Graphics 属性的 OnPaint 方法使用 Graphics 对象,则不需要释放此对象。

关于 Pen、Brush 等,如果将频繁地重新绘制窗体,则将这些变量定义为全局变量可以提高性能,因为在每一次重新绘制时都不需要再重新创建这些对象上浪费时间,但另一方面,定义全局变量将占用更多的内存资源。

注意:有时使用浮点数据类型代替整数类型可以改善绘图的质量,尽管浮点数据会占用更多的资源。

双缓存和无抖动绘图

双缓存技术用于通过减少抖动来提供更快、更平滑的绘图。在这种技术中,所有的对象都是使用一个临时的图像和一个 Graphics 对象在一个屏幕外的画布上绘制的。然后这个图像将复制到控件上。

如果绘图操作很简单,并且只包括绘制一些矩形或直线等简单的对象,则不需要使用双缓存技术,因为技术会降低性能。如果操作包含很多计算或绘图元素,则通过使用双缓存技术可以极大地改善性能

和外观。

理解 SetStyle 方法

Windows Forms 控件为双缓存提供了内建的支持,而 Control 类的 SetStyle 方法在这个过程中起到了非常重要的作用。

this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);

注意:很多控件(如 PictureBox)都是自动双缓存的,这意味着在 PictureBox 控件中查看图象时,我们不需要编写任何附加的代码。  

 绘制图象的质量和性能

       //质量优先:较低的绘图性能和较高的质量
            g.SmoothingMode= SmoothingMode.HighQuality;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            //性能优先:较低的质量和较高的性能
            g.SmoothingMode = SmoothingMode.HighSpeed;
            g.SmoothingMode = SmoothingMode.None;
            //文本的质量
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

只重新绘制所需的区域

使用区域和剪辑矩形可能会有些帮助。如果需要使用搞锯齿处理绘制一个对象,则只为此对象设置抗锯齿处理,而不要为整个绘图表面(窗体)设置此选项。使用区域是只重新绘制所需区域的最佳技术之一。如何使用特定区域无效和剪辑特定区域的详细信息,请看第6章。

使用图形路径绘制

             Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            Pen blackPen = new Pen(Color.Black, 2);
            GraphicsPath path = new GraphicsPath();
            path.AddLine(50, 50, 200, 50);
            path.AddLine(50, 50, 50, 200);
            path.AddRectangle(new Rectangle(60, 60, 150, 150));
            path.AddRectangle(new Rectangle(70, 70, 100, 100));
            path.AddEllipse(90, 90, 50, 50);
            g.DrawPath(blackPen, path);
            g.SmoothingMode = SmoothingMode.HighQuality;

            blackPen.Dispose();
            g.Dispose();        

使用一条图形路径绘制语句来代替多条绘制语句,在性能上有优势

但是有所限制,即我们不能使用不同的钢笔或画笔来绘制图形路径的每个元素(直线、矩形或椭圆等)。

同时绘制同一类元素的多个时,应该使用 绘制数组方法

例如:一次绘制三个矩形

 Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            Pen blackPen = new Pen(Color.Black, 2);
            RectangleF[] rectArray =
            {
                new RectangleF(5.0F,5.0F,100.0F,200.0F),
                new RectangleF(20.0F,20.0F,80.0F,40.0F),
                new RectangleF(60.0F,80.0F,140F,50.0F),
            };
            g.DrawRectangles(blackPen, rectArray);
            blackPen.Dispose();
            g.Dispose();

使用系统画笔和钢笔

Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            SolidBrush brush = (SolidBrush)SystemBrushes.ActiveCaption;
            Pen pn = SystemPens.ControlDarkDark;
            g.DrawLine(pn, 20, 20, 20, 100);
            g.DrawLine(pn, 20, 20, 100, 20);
            g.FillRectangle(brush, 30, 30, 50, 50);
            g.Dispose();

注意:系统画笔和钢笔不需要释放,如果释放会报异常。

避免图像的自动缩放

自动缩放会导致性能降低,尽量避免使用自动缩放。

 Graphics g = this.CreateGraphics();
            g.DrawImage(image, 10, 10, image.Width, image.Height);
            g.Dispose();

绘制时指定图像的宽和高。  

  

  

 

posted on 2024-02-14 16:11  宁静致远.  阅读(78)  评论(0编辑  收藏  举报