本文主要介绍 .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;
publicclass BasicX : Form {

 public BasicX() {
  InitializeComponent();
 }

 privatevoid 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();
 }

 privatevoid 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()]
 publicstaticvoid Main() {
  Application.Run(new BasicX());
 }
}

复制代码

  上述代码分成两个基本的步骤来创建示例程序。首先 InitializeComponent 方法包含一些属性的设置和附加窗体 Paint 事件的处理过程。注意,在方法中控件的样式也同时被设置,设置控件的样式也是自定义Windows 窗体及控件行为的一种有效途径,譬如:控件的"ResizeRedraw"属性指示当窗体的大小变化发生以后需要对其完全进行重绘,也就是说重绘时总是需 要对整个窗体的客户区域进行重绘。窗体的“客户区域”是指除了标题栏和边框的所有窗体区域。可以进行一个有趣的试验,取消该控件的属性然后再运行程序,我 们可以很明显的看出为什么该属性会被经常的设置,因为窗体调整大小后的无效区域根本不会被重绘。

  好了,我们需要注意一下BasicX_Paint方法,正如先前所提到的,Paint 事件在程序需要重绘时被激活,程序窗体利用Paint事件来负责回应需要重绘的系统消息,BasicX_Paint方法的调用需要一个对象 sender 和一个PaintEventArgs类型的变量,PaintEventArgs类的实例或称之为变量 e 封装了两个重要的数据,第一个就是窗体的 Graphics 对象,该对象表示窗体可绘制的表面也称之为画布用于绘制诸如线、文本以及图像等,第二个数据就是ClipRectangle,该Rectangle对象表 示窗体上无效的的矩形范围,或者说就是窗体需要重绘的区域。记住,当窗体的ResizeRedDraw设置后,调整大小后该ClipRectangle的 大小实际就等于窗体整个客户区域的大小,或者是被其它程序窗体遮盖的那部分剪切区域。关于部分剪切区域的用处我们会在智能重绘章节作更详细的阐述。

  BasicX 示例程序的运行界面

  双重缓冲区绘图技术

  双重缓冲区技术能够使程序的绘图更加快速和平滑,有效减少绘制时的图像闪烁。该技术的基本原理是先将图像绘制到内存中的一块画布上,一旦所有的 绘制操作都完成了,再将内存中的画布推到窗体的或者控件的表面将其显示出来。通过这种操作后的程序能使用户感觉其更加快速和美观。

  下面提供的示例程序能够阐明双重缓冲区的概念和实现方法,这个示例所包含的功能已相当完整,且完全可以在实际应用中使用。在该章节后面还会提及该技术应该配合控件的一些属性设置才能达到更好的效果。

  要想领略双重缓冲区绘图技术所带来的好处就请运行SpiderWeb示例程序吧。程序启动并运行后对窗口大小进行调整,你会发现使用这种绘图算法的效率不高,并且在调整大小的过程中有大量的闪烁出现。

不具备双重缓冲区技术的SpiderWeb示例程序

  纵观程序的源码你会发现在程序Paint事件激活后是通过调用LineDrawRoutine方法来实现线的绘制的。 LineDrawRoutine方法有两个参数,第一个是Graphics对象是用于绘制线条的地方,第二个是绘图工具Pen对象用来画线条。代码相当简 单,一个循环语句,LINEFREQ常量等,程序从窗体表面的左下一直划线到其右上。请注意,程序使用浮点数来计算在窗体上的绘制位置,这样做的好处就是 当窗体的大小发生变化时位置数据会更加精确。

privatevoid 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对象后释放其占用的资源,那么整个绘制操作就完成了。

privatevoid SpiderWeb_Paint(object sender, PaintEventArgs e) {
 Graphics g = e.Graphics;
 Pen redPen =new Pen(Color.Red);
 //call our isolated drawing routing
 LineDrawRoutine(g, redPen);
 redPen.Dispose();
 g.Dispose();
}
复制代码

  那么到底作怎么样的改动才能使上面的SpiderWeb程序实现简单的双重缓冲区技术呢?原理其实相当简单,就是将应该画到窗体表面的绘制操作 改成先画到内存中的位图上,LineDrawRoutine向这个在内存中隐藏的画布执行同样的蜘蛛网绘制操作,等到绘制完毕再通过调用 Graphics.DrawImage方法将隐藏的画布上内容推到窗体表面来显示出来,最后,再加上一些小的改动一个高性能的绘图窗体程序就完成了。

  比较下面双重缓冲区绘图事件与前面介绍的简单绘图事件间的区别:

privatevoid SpiderWeb_DblBuff_Paint(object sender, PaintEventArgs e) {
 Graphics g = e.Graphics;
 Pen bluePen =new Pen(Color.Blue);
 //create our offscreen bitmap
 Bitmap localBitmap =new Bitmap(ClientRectangle.Width,ClientRectangle.Height);
 Graphics bitmapGraphics = Graphics.FromImage(localBitmap);
 //call our isolated drawing routing
 LineDrawRoutine(bitmapGraphics, bluePen);
 //push our bitmap forward to the screen
 g.DrawImage(localBitmap, 0, 0);
 bitmapGraphics.Dispose();

 bluePen.Dispose();
 localBitmap.Dispose();
 g.Dispose();
}
  

复制代码

上面的示例代码创建了内存位图对象,它的大小等于窗体的客户区域(就是绘图表面)的大小,通过调用Graphics.FromImage将内存中位 图的引用传递给Graphics对象,也就是说后面所有对该Graphics对象的操作实际上都是对内存中的位图进行操作的,该操作在C++中等同于将位 图对象的指针复制给Graphics对象,两个对象使用的是同一块内存地址。现在Graphics对象表示的是屏幕后方的一块画布,而它在双重缓冲区技术 中起到至关重要的作用。所有的线条绘制操作都已经针对于内存中的位图对象,下一步就通过调用DrawImage方法

From:http://www.cnblogs.com/jxsoft/archive/2011/03/16/1986169.html

转载于:https://www.cnblogs.com/wulin9005/archive/2012/03/15/2397228.html

(转).NET框架下使用双缓冲技术绘图相关推荐

  1. NET框架下使用双缓冲技术绘图

    from http://bbs.nju.edu.cn/blogcon?userid=godwin&file=1178541360 本文主要介绍 .Net 框架的基本绘图技术.通过简要的介绍和示 ...

  2. android 绘图 双缓存,Android开发之用双缓冲技术绘图

    双缓冲技术主要用在画图,动画效果上.其原理就是:将资源先载入到缓冲区,然后再将缓冲区整个载入到View上面去. 双缓冲技术可以有效防止闪烁.提高显示质量. DrawView.java: package ...

  3. java双缓冲绘图_Java双缓冲技术-绘图应用

    1屏幕产生闪烁的原因 由于在显示所绘制的图像时,调用了repaint方法.repaint方法被调用时,需要清除整个背景,然后才调用paint方法显示画面.这样,在清除背景和绘制图像的短暂时间间隔内被用 ...

  4. 双缓冲技术绘图原理及简单的VC实现

    为了增加自己对双缓冲绘图技术的理解,简要做个笔记(以Windows为例): 1.Windows 绘图原理  我们在 Windows 环境下看到各种元素,如菜单.按钮.窗口.图像,从根本上说,都是&qu ...

  5. [Winodows图形编程]初识双缓冲技术

    2019独角兽企业重金招聘Python工程师标准>>> 为完成PaintBoardDemo(本人设计的一个基于.NET Framework的WinForm的画图程序),过程中遇到的技 ...

  6. 《MFC游戏开发》笔记六 图像双缓冲技术:实现一个流畅的动画

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9334121 作者:七十一雾央 新浪微博:http:// ...

  7. HDFS 双缓冲技术核心源码剖析

    本文大纲 一.HDFS 是大数据的基石 我们都知道,HDFS 是大数据存储的基石,所有的离线数据都存储在 HDFS 上,而 NameNode 是存储所有元数据的地方(所谓元数据就是描述数据的数据,比如 ...

  8. 双缓冲技术(C# GDI)

    c#如何实现防窗体闪烁的功能.大家都会想到运用双缓冲技术,那么在c#中是如何做的? 1. 利用默认双缓冲 (1)在应用程序中使用双缓冲的最简便的方法是使用 .NET Framework 为窗体和控件提 ...

  9. VC绘图中的双缓冲技术

    VC绘图中的双缓冲技术 转自:VC 绘图,使用双缓冲技术实现 ********************所有的GDI绘图函数使用的都是逻辑坐标(逻辑范围)******************* **** ...

最新文章

  1. Objective-C RunTime 学习笔记 之 AutoReleasPool
  2. linux 中ans 用法,JSON简介以及用法汇总
  3. 解决TM2008的界面字体问题
  4. Ie html button消失,input 按钮在IE下显现不一致的兼容问题
  5. Java设计模式笔记(7)适配器模式
  6. android 退出函数,android – 关闭应用程序与退出按钮
  7. [android] 练习使用ListView(二)
  8. avue里面的select怎么设置默认值_mysql大量的waiting for table level lock怎么办
  9. list元素求和_LeetCode刷题实战82:删除排序链表中的重复元素 II
  10. ipv6正则表达式 java,用正则表达式解析IPv4跟IPv6地址字符串
  11. 03 入门 - 安装MVC 5和创建应用程序
  12. Linux下创建指定路径下的文件夹/文件,通过get_option()传递路径
  13. c++ 打印日志信息
  14. Node.js开发指南中的例子(mysql版)
  15. Qt_ERRO Rundefined reference to `vtable for XXX'
  16. 页面URL传递中文乱码
  17. WTS_ERAL_年假生成规则
  18. 合同智能审核软件-提高审查效率和准确性
  19. Linux远程管理常用命令(超全超详细)【持续更新】
  20. 黑苹果13.0.1驱动RTL 8125B 2.5G网卡失败故障排查

热门文章

  1. c语言使用函数累加由n个a构成的整数之和,c 语言使用函数累加由n个a构成的整数之和...
  2. php dimage加上域名,PHP全功能无变形图片裁剪操作类与用法示例
  3. delphi 到出execl2010 文件损坏_Win7系统出现explorer.exe损坏的图像的解决方法是什么?...
  4. css a标签去掉下划线_CSS入门知识汇总
  5. LVS(5)——关于ipvsadm第一次启动失败的原因
  6. python中items属性的用法
  7. 关于DRAM、SRAM、cache、cpu、寄存器、主存之间的联系与区别
  8. 关于安卓Apk反编译 再编译回来不能正常安装的问题
  9. Pixhawk代码分析-姿态解算篇B
  10. TCP滑动窗口和拥塞控制机制