




已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#高效绘图来源:/suncherrydream/article/details/17585201双缓冲技术双缓冲是将图片在显示到DC前,现在要内存建一个DC,也就是用于存储这张图片的内存区,然后在将这部分update到你要显示的地方这样,可以防止画面抖动很大这样和你说吧,如果要实现你要的效果,你必须用指针访问内存比如,把程序声明成unsafe的,然后按照上面的操作进行this.clear(this.BackColor)不行的 invalidate(),闪的厉害 所以不行我再来详细解释一下刚才实现双缓冲的具体步骤:1、 在内存中建立一块“虚拟画布”:Bitmap bmp = new Bitmap(600, 600);2、 获取这块内存画布的Graphics引用:Graphics g = Graphics.FromImage(bmp);3、 在这块内存画布上绘图:g.FillEllipse(brush, i * 10, j * 10, 10, 10);4、将内存画布画到窗口中this.CreateGraphics().DrawImage(bmp, 0, 0);重点:现在的cpu飞快,其实数学计算一般很快,cpu大部分时间是在处理绘图,而绘图有三种境界:1每次重绘整体Invalidate()2每次局部绘制Invalidate(Rect); 3有选择的局部绘制。不能说,一定是第三种方式好,得视情况,境界高程序肯定就复杂,如果对效率要求不高或者绘图量小当然直接用第一种方式。然而,稍微专业点的绘图程序,第一第二种方式肯定满足不了要求,必须选用第三种方式。而第三种方式的手段多样,也得根据实际情况拿相应的解决之道。这里讲解一般的三种手段,他们可以联合使用。1. 缓存Bitmap或者DoubleBuffer。缓存就是先把绘制的图形绘制到一张内存位图上,然后在一次性的贴位图,他可以提高绘图速度,也能避免闪烁。DoubleBuffer=true是C#窗体的属性,设置了此属性估计系统本身会起用无效区的内存位图缓存,而不需要程序员Bitmap处理。2. 合理利用无效区域。无效区域就是系统保存当前变化需要重绘的区域,可以在OnPaint()中,e.ClipRectangle(e.ClipRectangle.X)直接获得,也可以通过其他方式获得。Windows系统只会重绘无效区域内的绘图信息,然而我们用户的绘制代码一般是绘制整个区域的,很多时候无效区域只是一小部分区域,虽然执行了所有的绘图代码,但是Windows系统只会重新更新无效区域内的绘图。这里有两个利用点:1用户请求重绘时,只请求重绘指定区域的,而不是整个区域,如Invalidate(Rect);2在用户绘图代码Graphics g; g.DrawLineg.DrawStringg.FillRectangle.前,先判断绘图的内容是否在无效区域,如果不是就不直接g.Draw.绘图代码。3. 直接贴图。一般绘图或者重绘是Windows根据无效区域绘制的,如果在鼠标移动时需要重绘通过Windows系统处理Paint消息,有时满足不了要求,比如鼠标移动绘制十字测量线就得用异或线而不是Paint消息,又比如鼠标移动绘制跟随的信息提示框需要频繁擦除上次覆盖的背景,又比如台球滚动时台球与球桌背景的关系。类似的这些问题如何解决?首先肯定不能利用Windows原来的绘图机制。其中一种解决方式是,不断的帧间变化区域贴内存位图中的信息框每次鼠标位置变化时可以重新g.Draw.或者贴早生成的信息框内存位图,中被信息框覆盖的背景应该把本来的大背景截取此需要擦除区域的位置大小位图贴回来就是擦除背景了。由于每次大背景发生变化时,都应会重新生成大背景内存位图,所以可以是变化的背景。这三种方式可以一起使用,应该可以解决中等的绘图项目的效率问题。中大型的绘图,必须记住两点1只绘制电脑屏幕能显示的部分;2只绘制变化的部分。C#GDI+双缓冲高效绘图Rectangle rectangle = e.ClipRectangle;/取出次窗体或者画布的有效区的矩形区域BufferedGraphicsContext GraphicsContext = BufferedGraphicsManager.Current;/获取程序住缓冲区域的BufferedGraphicsContext(双缓存类,此类用于提供双缓冲的功能)对象BufferedGraphics myBuffer = GraphicsContext.Allocate(e.Graphics, e.ClipRectangle);/获取缓冲区Graphics g = myBuffer.Graphics;指定在呈现期间像素偏移的方式。g.PixelOffsetMode = PixelOffsetMode.HighQuality;/高质量低速度呈现指定是否将平滑处理(消除锯齿)应用于直线、曲线和已填充区域的边缘。g.SmoothingMode = SmoothingMode.HighQuality;/ 指定高质量、低速度呈现。g.Clear(BackColor);/或者使用invalidate方法=有效区的擦除Pen bluePen2 = new Pen(Color.Blue);LineDrawRoutine(g, bluePen2);myBuffer.Render(e.Graphics); /将图形缓冲区的内容写入指定的Graphics对象。g.Dispose();myBuffer.Dispose();其实在C#里如果是在Form中绘图的话直接把Form的DoubleBuffered = true就可以了(利用winfrom窗体的默认双缓冲)把所有的绘图放在一个picturebox里面绘制,不要直接再在form里面绘SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.Selectable, true);如果你在Form中绘图的话,不论是不是采用的双缓存,都会看到图片在更新的时候都会不断地闪烁,解决方法就是在这个窗体的构造函数中增加以下三行代码:请在构造函数里面底下加上如下几行:SetStyle(ControlStyles.UserPaint, true);SetStyle(ControlStyles.AllPaintingInWmPaint, true); / 禁止擦除背景.SetStyle(ControlStyles.DoubleBuffer, true); / 双缓冲参数说明:UserPaint如果为true,控件将自行绘制,而不是通过操作系统来绘制。此样式仅适用于派生自 Control的类。AllPaintingInWmPaint如果为true,控件将忽略 WM_ERASEBKGND窗口消息以减少闪烁。仅当UserPaint 位设置为true时,才应当应用该样式。DoubleBuffer如果为true,则绘制在缓冲区中进行,完成后将结果输出到屏幕上。双重缓冲区可防止由控件重绘引起的闪烁。要完全启用双重缓冲,还必须将UserPaint和AllPaintingInWmPaint样式位设置为 true。GDI+的双缓冲问题我想有很多搞图形方面的朋友都会用到双缓冲技术的时候,而且有的时候她的确是个头疼的问题。最近我也要用双缓冲技术,程序怎么调试都不合适,当要对图形进行移动时,总是会出现闪烁抖动。在网上找了些资料,说得都不清不楚的,折腾了一晚上也没弄出来。第二天觉定自己研究一下。现在把自己的一些想法拿出来跟大家分享一下。双缓冲的基本原理:一直以来的误区:.net1.1 和 .net 2.0 在处理控件双缓冲上是有区别的。.net 1.1中,使用:this.SetStyle(ControlStyles.DoubleBuffer, true);.net 2.0中,使用:this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);要知道,图元无闪烁的实现和图元的绘制方法没有多少关系,只是绘制方法可以控制图元的刷新区域,使双缓冲性能更优!导致画面闪烁的关键原因分析:一、绘制窗口由于大小位置状态改变进行重绘操作时绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。刷新过程中会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现。所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。特别是图元比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。解决上述问题的关键在于:窗口刷新一次的过程中,让所有图元同时显示到窗口。二、进行鼠标跟踪绘制操作或者对图元进行变形操作时当进行鼠标跟踪绘制操作或者对图元进行变形操作时,Paint事件会频繁发生,这会使窗口的刷新次数大大增加。虽然窗口刷新一次的过程中所有图元同时显示到窗口,但也会有时间延迟,因为此时窗口刷新的时间间隔远小于图元每一次显示到窗口所用的时间。因此闪烁现象并不能完全消除!所以说,此时导致窗口闪烁现象的关键因素在于Paint事件发生的次数多少。解决此问题的关键在于:设置窗体或控件的几个关键属性。下面讲具体的实现方法:(转)1、在内存中建立一块“虚拟画布”:Bitmap bmp = new Bitmap(600, 600);2、获取这块内存画布的Graphics引用:Graphics g = Graphics.FromImage(bmp);3、在这块内存画布上绘图:如画线g.DrawLine(添加参数);4、将内存画布画到窗口中:this.CreateGraphics().DrawImage(bmp, 0, 0);在构造函数中加如下代码代码一:SetStyle(ControlStyles.UserPaint, true);SetStyle(ControlStyles.AllPaintingInWmPaint, true); / 禁止擦除背景.SetStyle(ControlStyles.DoubleBuffer, true); / 双缓冲或代码二:this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |ControlStyles.AllPaintingInWmPaint, true);this.UpdateStyles();上述方式适合直接在窗体上绘制图形,并且很容易做到。但有时我们需要在某个控件上绘制图形,那该怎么办呢?原理跟直接在窗体上绘制图形采用双缓冲是一样的,也要在控件的构造函数里设置上述代码一或代码二。那么又怎么设置呢?在Microsoft Visual Studio 2005环境下的,用的C#语言,并采用GDI+。目标是实现简单的鼠标拖动画线,并且要把之前画过的线都重新画出来。整个程序使用了三个控件:一个SplitContainer控件、一个自定义的Panel控件和一个VS自带的Panel控件。SplitContainer控件的大小设置成窗体宽、半窗体高并定位在窗体的下半部分。自定义的Panel控件和VS自带的Panel控件都是通过设置它们的Dock属性使它们绑定到SplitContainer控件的Panel1和Panel2上。附录中会说到自定义的Panel控件是怎么定义的。窗体的上半部分采用双缓冲。自定义的Panel控件采用了双缓冲,是通过在自定义Panel控件时设置样式来做到的(设置方法与窗体的双缓冲设置方法一样,如下面三条语句),这不能够在面板的Paint方法里直接设置,因为SetStyle()在Panel类中不是public方法。VS自带的Panel控件没有采用双缓冲。SetStyle(ControlStyles.AllPaintingInWmPaint, true);SetStyle(ControlStyles.UserPaint, true);SetStyle(ControlStyles.OptimizedDoubleBuffer, true);把三者结合有两种方式来创建Graphics对象:第一是在内存上创建一块和显示区域或控件相同大小的画布,在这块画布上创建Graphics对象。接着所有的图元都在这块画布上绘制,绘制完成以后再使用该画布覆盖显示控件的背景,从而达到“显示一次仅刷新一次”的效果!第二是直接在内存上创建Graphics对象。使用双缓冲的图形可以减少或消除重绘显示图面时产生的闪烁。使用双缓冲时,更新的图形首先被绘制到内存的缓冲区中,然后,此缓冲区的内容被迅速写入某些或所有显示的图面中。显示图形的重写相对简短,这通常可以减少或消除有时在更新图形时出现的闪烁。双缓冲技术(C# GDI)c#如何实现防窗体闪烁的功能。大家都会想到运用双缓冲技术,那么在c#中是如何做的?1、 利用默认双缓冲(1)在应用程序中使用双缓冲的最简便的方法是使用 .NET Framework 为窗体和控件提供的默认双缓冲。通过将 DoubleBuffered 属性设置为 true。this.DoubleBuffered=true;(2)使用 SetStyle 方法可以为 Windows 窗体和所创作的 Windows 控件启用默认双缓冲。SetStyle(ControlStyles.OptimizedDoubleBuffer, true);2、 手工设置双缓冲.netframework提供了一个类BufferedGraphicsContext负责单独分配和管理图形缓冲区。每个应用程序域都有自己的默认 BufferedGraphicsContext 实例来管理此应用程序的所有默认双缓冲。大多数情况下,每个应用程序只有一个应用程序域,所以每个应用程序通常只有一个默认 BufferedGraphicsContext。默认 BufferedGraphicsContext 实例由 BufferedGraphicsManager 类管理。通过管理BufferedGraphicsContext实现双缓冲的步骤如下:(1)获得对 BufferedGraphicsContext 类的实例的引用。(2)通过调用 BufferedGraphicsContext.Allocate 方法创建 BufferedGraphics 类的实例。(3)通过设置 BufferedGraphics.Graphics 属性将图形绘制到图形缓冲区。(4)当完成所有图形缓冲区中的绘制操作时,可调用 BufferedGraphics.Render 方法将缓冲区的内容呈现到与该缓冲区关联的绘图图面或者指定的绘图图面。(5)完成呈现图形之后,对 BufferedGraphics 实例调用释放系统资源的 Dispose 方法。完整的例子,在一个400*400的矩形框内绘制10000个随机生成的小圆。BufferedGraphicsContext current = BufferedGraphicsManager.Current; /(1)BufferedGraphics bg = current.Allocate(this.CreateGraphics(),this.DisplayRectangle); /(2)Graphics g = bg.Graphics;/(3)/随机 宽400 高400System.Random rnd = new Random();int x,y,w,h,r,i;for (i = 0; i 10000; i+)x = rnd.Next(400);y = rnd.Next(400);r = rnd.Next(20);w = rnd.Next(10);h = rnd.Next(10);g.DrawEllipse(Pens.Blue, x, y, w, h);bg.Render();/(4)/bg.Render(this.CreateGraphics();bg.Dispose();/(5)BufferedGraphicsContext current = BufferedGraphicsManager.Current; /(1)BufferedGraphics bg;bg = current.Allocate(this.CreateGraphics(),this.DisplayRectangle); /(2)Graphics g = bg.Graphics;/(3)/随机 宽400 高400System.Random rnd = new Random();int x,y,w,h,r,i;for (i = 0; i 10000; i+)x = rnd.Next(400);y = rnd.Next(400);r = rnd.Next(20);w = rnd.Next(10);h = rnd.Next(10);g.DrawEllipse(Pens.Blue, x, y, w, h);bg.Render();/(4)/bg.Render(this.CreateGraphics();bg.Dispose();/(5)3、 自己开辟一个缓冲区(如一个不显示的Bitmap对象),在其中绘制完成后,再一次性显示。完整代码如下:view plaincopy to clipboardprint?Bitmap bt = new Bitmap(400, 400);Graphics bg = Graphics.FromImage(bt);System.Random rnd = new Random();int x, y, w, h, r, i;for (i = 0; i 10000; i+)x = rnd.Next(400);y = rnd.Next(400);r = rnd.Next(20);w = rnd.Next(10);h = rnd.Next(10);bg.DrawEllipse(Pens.Blue, x, y, w, h);this.CreateGraphics().DrawImage(bt, new Point(0, 0);BufferedGraphicsContext的构造函数 BufferedGraphicsContext初始化BufferedGraphicsContext 类的新实例。BufferedGraphicsContext的方法 Allocate(Graphics, Rectangle)使用指定的Graphics 的像素格式,创建指定大小的图形缓冲区。 Allocate(IntPtr, Rectangle)使用指定的Graphics 的像素格式,创建指定大小的图形缓冲区。 DisposeReleases all resources used by theBufferedGraphicsContext. Equals(Object)确定指定的Object 是否等于当前的Object。(继承自Object。) Finalize允许Object 在“垃圾回收”回收Object 之前尝试释放资源并执行其他清理操作。(继承自Object。) GetHashCode用作特定类型的哈希函数。 (继承自Object。) GetType获取当前实例的Type。(继承自Object。) Invalidate如果某个缓冲区已被分配但尚未释放,则释放当前的图形缓冲区。 MemberwiseClone创建当前Object 的浅表副本。(继承自Object。) ToString返回表示当前Object 的String。(继承自Object。)BufferedGraphicsContext的属性 MaximumBuffer获取或设置要使用的缓冲区的最大大小。双缓冲技术绘图本文主要介绍 .Net 框架的基本绘图技术。通过简要的介绍和示例程序来探讨绘图技术的优势、劣势以及其它相关注意事项。简介幸运的是当编写一个典型的Windows 窗体程序时,窗体和控件的绘制、效果等操作是不需要特别加以考虑的。这是为什么呢?因为通过使用 .Net 框架,开发人员可以拖动一系列的控件到窗体上,并书写一些简单的与事件相关联的代码然后在IDE中按F5,一个完完全全的窗体程序就诞生了!所有控件都将自己绘制自己,窗体或者控件的大小和缩放都调整自如。在这里经常会用到的,且需要引起一点注意的就是控件效果。游戏,自定义图表控件以及屏幕保护程序的编写会需要程序员额外撰写用于响应 Paint 事件的代码。本文针对那些Windows 窗体开发人员并有助于他们在应用程序编制过程中使用简单的绘图技术。首先,我们会讨论一些基本的绘图概念。到底谁在负责进行绘制操作?Windows 窗体程序是如何知道何时该进行绘制的?那些绘制代码究竟被放置在哪里?之后,还将介绍图像绘制的双重缓冲区技术,你将会看到它是怎样工作的,怎样通过一个方法来实现缓存和实际显示的图像间的交替。最后,我们将会探讨”智能无效区域”,实际就是仅仅重绘或者清除应用程序窗体上的无效部分,加快程序的显示和响应速度。希望这些概念和技术能够引导读者阅读完本文,并且有助于更快和更有效的开发Windows 窗体程序。Windows 窗体使用GDI+图像引擎,在本文中的所有绘图代码都会涉及使用托管的.Net框架来操纵和使用Windows GDI+图像引擎。尽管本文用于基本的窗体绘图操作,但是它同样提供了快速的、有效的且有助于提高程序性能的技术和方法。所以,在通读本文之前建议读者对.Net框架有个基本的了解,包括Windows 窗体事件处理、简单的GDI+对象譬如Line,Pen和Brush等。熟悉Visual Basic.Net或者C#编程语言。概念Windows 应用程序是自己负责绘制的,当一个窗体”不干净”了,也就是说窗体改变了大小,或者部分被其它程序窗体遮盖,或者从最小化状态恢复时,程序都会收到需要绘制的信息。Windows把这种”不干净”状态称为”无效的(Invalidated)”状态,我们理解为:需要重绘,当Windows 窗体程序需要重绘窗体时它会从Windows消息队列中获取绘制的信息。这个信息经过.Net框架封装然后传递到窗体的 PaintBackground 和 Paint 事件中去,在上述事件中适当的书写专门用于绘制的代码即可。简单的绘图示例如下:using System;using System.Drawing;using System.Windows.Forms;public class BasicX : Form public BasicX() InitializeComponent();private void BasicX_Paint(object sender, PaintEventArgs e) Graphics g = e.Graphics;Pen p = new Pen(Color.Red);int width = ClientRectangle.Width;int height= ClientRectangle.Height;g.DrawLine(p, 0,0, width, height);g.DrawLine(p, 0, height, width, 0);p.Dispose();private void InitializeComponent() this.SetStyle(ControlStyles.ResizeRedraw, true);this.ClientSize = new System.Drawing.Size(300, 300);this.Text = BasicX;this.Paint += new PaintEventHandler(this.BasicX_Paint);System.STAThreadAttribute()public static void Main() Application.Run(new BasicX();上述代码分成两个基本的步骤来创建示例程序。首先 InitializeComponent 方法包含一些属性的设置和附加窗体 Paint 事件的处理过程。注意,在方法中控件的样式也同时被设置,设置控件的样式也是自定义Windows 窗体及控件行为的一种有效途径,譬如:控件的ResizeRedraw属性指示当窗体的大小变化发生以后需要对其完全进行重绘,也就是说重绘时总是需要对整个窗体的客户区域进行重绘。窗体的“客户区域”是指除了标题栏和边框的所有窗体区域。可以进行一个有趣的试验,取消该控件的属性然后再运行程序,我们可以很明显的看出为什么该属性会被经常的设置,因为窗体调整大小后的无效区域根本不会被重绘。好了,我们需要注意一下BasicX_Paint方法,正如先前所提到的,Paint 事件在程序需要重绘时被激活,程序窗体利用Paint事件来负责回应需要重绘的系统消息,BasicX_Paint方法的调用需要一个对象 sender 和一个PaintEventArgs类型的变量,PaintEventArgs类的实例或称之为变量 e 封装了两个重要的数据,第一个就是窗体的 Graphics 对象,该对象表示窗体可绘制的表面也称之为画布用于绘制诸如线、文本以及图像等,第二个数据就是ClipRectangle,该Rectangle对象表示窗体上无效的的矩形范围,或者说就是窗体需要重绘的区域。记住,当窗体的ResizeRedDraw设置后,调整大小后该ClipRectangle的大小实际就等于窗体整个客户区域的大小,或者是被其它程序窗体遮盖的那部分剪切区域。关于部分剪切区域的用处我们会在智能重绘章节作更详细的阐述。双重缓冲区绘图技术双重缓冲区技术能够使程序的绘图更加快速和平滑,有效减少绘制时的图像闪烁。该技术的基本原理是先将图像绘制到内存中的一块画布上,一旦所有的绘制操作都完成了,再将内存中的画布推到窗体的或者控件的表面将其显示出来。通过这种操作后的程序能使用户感觉其更加快速和美观。下面提供的示例程序能够阐明双重缓冲区的概念和实现方法,这个示例所包含的功能已相当完整,且完全可以在实际应用中使用。在该章节后面还会提及该技术应该配合控件的一些属性设置才能达到更好的效果。要想领略双重缓冲区绘图技术所带来的好处就请运行SpiderWeb示例程序吧。程序启动并运行后对窗口大小进行调整,你会发现使用这种绘图算法的效率不高,并且在调整大小的过程中有大量的闪烁出现。纵观程序的源码你会发现在程序Paint事件激活后是通过调用LineDrawRoutine方法来实现线的绘制的。LineDrawRoutine方法有两个参数,第一个是Graphics对象是用于绘制线条的地方,第二个是绘图工具Pen对象用来画线条。代码相当简单,一个循环语句,LINEFREQ常量等,程序从窗体表面的左下一直划线到其右上。请注意,程序使用浮点数来计算在窗体上的绘制位置,这样做的好处就是当窗体的大小发生变化时位置数据会更加精确。private void LineDrawRoutine(Graphics g, Pen p) float width = ClientRectangle.Width;float height = ClientRectangle.Height;float xDelta = width / LINEFREQ;float yDelta = height / LINEFREQ;for (int i = 0; i LINEFREQ; i+) g.DrawLine(p, 0, height - (yDelta * i), xDelta * i, 0);撰写很简单的用于响应Paint事件SpiderWeb_Paint的代码,正如前面所提到的,Graphics对象就是从Paint事件参数PaintEventArgs对象中提取出来的表示窗体的绘制表面。这个Graphics对象连同新创建Pen对象一起传递给LineDrawRoutine方法来画出蜘蛛网似的线条,使用完Graphics对象和Pen对象后释放其占用的资源,那么整个绘制操作就完成了。private void SpiderWeb_Paint(object sender, PaintEventArgs e) Graphics g = e.Graphics;Pen redPen = new Pen(Color.Red);/call our isolated drawing routingLineDrawRoutine(g, redPen);redPen.Dispose();g.Dispose();那么到底作怎么样的改动才能使上面的SpiderWeb程序实现简单的双重缓冲区技术呢?原理其实相当简单,就是将应该画到窗体表面的绘制操作改成先画到内存中的位图上,LineDrawRoutine向这个在内存中隐藏的画布执行同样的蜘蛛网绘制操作,等到绘制完毕再通过调用Graphics.DrawImage方法将隐藏的画布上内容推到窗体表面来显示出来,最后,再加上一些小的改动一个高性能的绘图窗体程序就完成了。比较下面双重缓冲区绘图事件与前面介绍的简单绘图事件间的区别:private void SpiderWeb_DblBuff_Paint(object sender, PaintEventArgs e) Graphics g = e.Graphics;Pen bluePen = new Pen(Color.Blue);/create our offscreen bitmapBitmap localBitmap = new Bitmap(ClientRectangle.Width,ClientRectangle.Height);Graphics bitmapGraphics = Graphics.FromImage(localBitmap);/call our isolated drawing routingLineDrawRoutine(bitmapGraphics, bluePen);/push our bitmap forward to the screeng.DrawImage(localBitmap, 0, 0);bitmapGraphics.Dispose();bluePen.Dispose();localBitmap.Dispose();g.Dispose();上面的示例代码创建了内存位图对象,它的大小等于窗体的客户区域(就是绘图表面)的大小,通过调用Graphics.FromImage将内存中位图的引用传递给Graphics对象,也就是说后面所有对该Graphics对象的操作实际上都是对内存中的位图进行操作的,该操作在C+中等同于将位图对象的指针复制给Graphics对象,两个对象使用的是同一块内存地址。现在Graphics对象表示的是屏幕后方的一块画布,而它在双重缓冲区技术中起到至关重要的作用。所有的线条绘制操作都已经针对于内存中的位图对象,下一步就通过调用DrawImage方法将该位图复制到窗体,蜘蛛网的线条就会立刻显示在窗体的绘制表面而且丝毫没有闪烁出现。这一系列的操作完成后还不是特别有效,因为我们先前提到了,控件的样式也是定义Windows 窗体程序行为的一条途径,为了更好的实现双重缓冲区必须设置控件的Opaque属性,这个属性指明窗体是不负责在后台绘制自己的,换句话说,如果这个属性设置了,那么必须为清除和重绘操作添加相关的代码。具备双重缓冲区版本的SpiderWeb程序通过以上的设置在每一次需要重绘时都表现良好,窗体表面用其自己的背景色进行清除,这样就更加减少了闪烁的出现。public SpiderWeb_DblBuff() SetStyle(ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);private void SpiderWeb_DblBuff_Paint(object sender, PaintEventArgs e) /create our offscreen bitmapBitmap localBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);Graphics bitmapGraphics = Graphics.FromImage(localBitmap);bitmapGraphics.Clear(BackColor);/call our isolated drawing routingLineDrawRoutine(bitmapGraphics, bluePen);结果怎么样?图像的绘制平滑多了。从内存中将蜘蛛网的线条推到前台以显示出来是完全没有闪烁的,但是我们还是稍微停顿一下,先将内存中的位图修整一下再显示出来,可以添加一行代码以便使线条看上去更加平坦。bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;在将内存中的位图对象赋给Graphics后通过放置这行代码,我们在画布上所画的每一个线条都使用了反锯齿,使凹凸不平的线条显得更加平坦。完成了简单的双重缓冲区应用后有两个问题需要向读者阐明,.Net中的某些控件例如:Button、PictureBox、Label还有PropertyGrid都已经很好的利用了该技术!这些控件在默认状态下会自动启用双重缓冲区技术,用户可以通过对“DoubleBuffer”属性的设置来就可以实现双重缓冲区技术。所以,用户若使用PictureBox来绘制蜘蛛网将会更有效率一些,而且也使程序变得更加简单了。我们在这里讨论的双重缓冲区技术既不是完全被优化但也没有什么太大的负面影响。双重缓冲区技术是减少Windows 窗体绘制时闪烁的一条重要途径,但是它也确实消耗不少内存,因为它将会使用双倍的内存空间:应用程序所显示的图像和屏幕后方内存中的图像。每次Paint事件被激活时都会动态的创建位图对象,这种机制会相当耗费内存。而自带双重缓冲区技术的控件在使用DoubleBuffer属性后执行起来的优化程度则会更好一些。使用GDI+的DIB(与设备无关的位图)对象来实现这种画面以外的内存缓冲,自带双重缓冲区机制的控件则能好的利用该位图对象。DIB是底层Win32的对象用于高效的屏幕绘制。同样,值得注意的是GDI+的第一个版本GDI中仅与硬件加速有关以及一些简单功能可以直接使用,由于这样的限制,像反锯齿和半透明等屏幕绘制方法执行起来的速度则相当慢。尽管双重缓冲区机制消耗了一些内存但是它的使用不容置疑的增强了程序的执行性能。智能重绘,在绘制前需要斟酌一下“智能无效”(智能重绘)就是在暗示程序员应该明白仅应对程序中无效的区域进行重绘,对Regions对象所对应的无效区域进行重绘可以提高绘制性能,使用Regions对象你可以仅排除或绘制控件和窗体的部分区域已获得更好的性能。我们现在就开始来看一下BasicClip示例程序,这个程序使用保存在PaintEventArgs对象的ClipRectangle对象,之前我们已经提及,无论何时当程序的大小发生变化时Paint事件都会被激活。BasicClip示例程序用红和蓝两种颜色填充剪切的矩形区域,利用不同的速度调整窗体的大小几次以后,你会发现绘制的矩形区域其实就是窗体的无效区域(包括大于原始窗体大小的区域部分和缩少了的区域部分),示例程序的Paint事件代码如下:private void BasicClip_Paint(object sender, PaintEventArgs e) Graphics g = e.Graphics;/swap colorsif (currentBrush.Color = Color.Red)currentBrush.Color = Color.Blue;elsecurrentBrush.Color = Color.Red;g.FillRectangle(currentBrush, e.ClipRectangle);g.Dispose();该示例程序的唯一目的就是演示怎样仅针对部分区域进行图形绘制。Regions是一种被用来定义Windows 窗体或者控件区域的对象,调整窗体大小后所获得的Region
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 作业布置创建鼠标点击交互脚本16课件
- 二零二五年度国际贸易风险管理合同范本
- 二零二五年度商业地产锅炉供暖设施租赁经营协议
- 水电厂电工基础知识培训课件
- 二零二五年瓷砖材料品质保障采购协议
- 二零二五年度民宿改造与运营管理合同
- 2025版房地产项目营销手续代办服务合同范本
- 二零二五年度房地产项目绿色生态社区建设委托管理合同
- 二零二五版房地产项目投资咨询服务合同
- 2025版木门品牌授权与区域代理销售合同
- (新)部编人教版高中历史中外历史纲要上册《第13课-从明朝建立到清军入关课件》讲解教学课件
- 医药行业专题报告:VCTE技术(福瑞股份子公司)专利概览
- GB/T 42430-2023血液、尿液中乙醇、甲醇、正丙醇、丙酮、异丙醇和正丁醇检验
- 关于规范学校中层及以上领导干部岗位设置及任免办法
- 《现代汉语》课件修辞
- 某园区综合运营平台项目建议书
- 创造适合教育(2017年0613)
- 微创外科课件
- 易驱ED3000系列变频器说明书
- 农机行政处罚流程图
- GB∕T 6818-2019 工业用辛醇(2-乙基己醇)
评论
0/150
提交评论