C#发现之旅第四讲 Windows图形开发入门

时间:2023-01-21 08:52:41
C#发现之旅第四讲 Windows图形开发入门

袁永福 2008-5-15

系列课程说明

C#发现之旅第四讲 Windows图形开发入门     为了让大家更深入的了解和使用C#,我们将开始这一系列的主题为“C#发现之旅”的技术讲座。考虑到各位大多是进行WEB数据库开发的,而所谓发现就是发现我们所不熟悉的领域,因此本系列讲座内容将是C#在WEB数据库开发以外的应用。目前规划的主要内容是图形开发和XML开发,并计划编排了多个课程。在未来的C#发现之旅中,我们按照由浅入深,循序渐进的步骤,一起探索和发现C#的其他未知的领域,更深入的理解和掌握使用C#进行软件开发,拓宽我们的视野,增强我们的软件开发综合能力。

本系列课程配套的演示代码下载地址为 http://files.cnblogs.com/xdesigner/cs_discovery.zip

本系列课程已发布的文章有
C#发现之旅第一讲 C#-XML开发
C#发现之旅第二讲 C#-XSLT开发
C#发现之旅第三讲 使用C#开发基于XSLT的代码生成器
C#发现之旅第四讲 Windows图形开发入门
C#发现之旅第五讲 图形开发基础篇
C#发现之旅第六讲 C#图形开发中级篇
C#发现之旅第七讲 C#图形开发高级篇
C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
C#发现之旅第九讲 ASP.NET验证码技术
C#发现之旅第十讲 文档对象模型

次课程说明

    本课程是Windows图形开发入门,算是图形开发知识扫盲,主要介绍图形编程的一些基础理论知识,并无配套演示源代码。其中包括

  1. WEB数据库开发和图形开发的比较
  2. Windows图形子系统基本原理
  3. 图形设备上下文
  4. 矢量图形和位图
  5. 图形坐标系统
  6. 图形界面基本元素
  7. 用户界面事件

    在此我假设各位具有一定的计算机软件开发基础,了解基本的计算机软硬件知识,但对Windows图形开发则理解模糊,不甚了解。因此就介绍一下Windows图形开发的基本原理,并不涉及到实际的开发,未来的序列培训中将以本次培训为基础,使用C#进行实际的Windows图形开发演示。

WEB数据库开发和图形开发的比较

    现来讲讲WEB数据库开发和图形开发的比较。大家大多是搞WEB数据库开发的,其用户界面基本上都是依赖HTML来进行描述,其实桌面开发也是大有可为的,而桌面开发中很重要的一部分就是图形开发。图形开发和Web开发相比具有很大的不同,其开发思想,技术手段,调试技巧等有着很大的不同现按以下几个方面进行简单说明。

面向的领域

    Web数据库编程和图形开发存在比较大的区别,Web数据库编程大部分是面向工程开发的,其中充满了各种业务数据结构,业务逻辑处理。而图形开发相对而言技术因素更多些,面向的领域比较专业和底层。对于那些想在纯粹的技术上所有突破的人来说,图形开发是一种不错的选择。

难度

    图形开发比较难于学习和掌握,因此熟练掌握图形开发的开发人员相对比较少,而且各种软件技能培训机构都提供对WEB数据库开发的培训,而提供图形开发培训的则很少。难就人少,人少竞争就少,因此图形软件开发能力就成为一种与众不同的软件开发能力。

与数据库的关系

    Web数据库应用系统比较依赖关系型数据库,数据库是其系统中最重要的部分。而图形开发则偏重于用户界面和图形文档输出,因此对数据库的依赖相对少些,很多图形软件的正常运行是不需要数据库的。

软件设计和开发

    比较复杂的图形开发需要使用大量的软件设计模式,有时还需要文档对象模型这种比较高级的软件设计模型,这些复杂的软件设计模式在常规的中小型WEB数据库开发中使用不多,因此深入学习图形开发将明显的增强开发者的软件设计能力。

    相对于Web数据库编程,图形开发在开发,调试和优化手段上有着很大的不同,在某些情况下,图形程序的调试是相当困难的,而图形程序所特有的抗闪烁优化过程是比较艰难的,非常考验开发者的软件开发能力。

应用

    在目前的企业信息化和电子政务中,WEB数据库开发模式占据着主流,但图形开发仍然具有很广泛的应用,而且很多是比较底层的,基础性的软件开发。比如WEB浏览器,VS.NET开发环境,甚至Windows操作系统本身都是图形开发的产品,WEB软件中的图表,曲线图等HTML难于展现的用户界面,一般也有赖于图形编程来实现。

展望

    对于很多人来说,图形开发是一个全新的开发领域,需要使用新的软件设计理验和开发模式,但图形开发也是一个丰富多彩的世界,有着非常多的技术等待大家的探索。图形开发虽然比较难,但仍然值得大家学习和使用。图形开发难度大,技术含量高,是一种优质的软件开发能力。若大家想探索新的技术领域,并获得与众不同的开发能力,那就可以从现在开始学习Windows图形开发。

Windows图形子系统基本原理

    Windows操作系统具有最明显的特点是具有图形化用户界面,这种技术大大改善了用户体验,使得大量的普通使用者能方便的学习和使用Windows操作系统,这是微软取得巨大成功的一个重要因素。

    Windows操作系统针对图形开发也提供了强大的编程接口,使得开发者可以方便的在Windows上面开发具有专业效果的图形化用户界面软件。在Windows以前,开发者要实现图形化用户界面,则需要具备相当多的计算机硬件知识,计算机软件业界在图形化用户界面方面进展缓慢,而Windows则提供了一个很方便的图形开发平台,使得大量的图形化用户界面软件迅速涌现,从而推动了计算机软件业界整体快速发展。

    Windows操作系统中包含了一个图形子系统,专门用于管理各种图形输出设备,包括显示器,打印机,绘图仪等。由于Windows系统启用保护模式,应用程序没有权限直接访问计算机硬件,因此都必须调用Windows的图形子系统来操作图形设备。下图就是Windows环境下图形软件的基本原理。

C#发现之旅第四讲 Windows图形开发入门

    Windows提供了一个GDI32.DLL,稍微了解图形开发的都知道这个DLL,它包含了大部分的Windows的图形子系统的API函数。各种开发语言,包括VB,VC,C#,Delphi等等都能调用这些API函数来进行图形开发。

    Windows通过这些API获得应用系统的图形操作请求后,内部进行一番处理,然后根据目标图形硬件调用相应的设备驱动程序。

    若应用系统请求在显示器上显示图形,则Windows会首先设置计算机显存,然后忙其他事,而显卡中有一个独立的处理器能自主访问显存,根据其中的数据来设置显示器中显示的内容。显卡是固定每过一段时间访问显存,刷新显示器,因此它有一个频率的参数。比如它的频率是50HZ,则它是每20毫秒访问显存,刷新显示器。显卡自己有处理器来进行这样的操作,这种操作算是硬件操作,其过程不受操作系统的感知和控制。理解这个原理,对理解和消除用户界面闪烁有着很大的帮助。

    若应用系统请求进行打印输出,则Windows首先将打印样式输出到打印任务队列中,然后调用打印机驱动程序进行文档的打印,由于具有打印任务队列,因此多个软件可同时进行打印输出,而不必等待打印机硬件空闲。在Windows2000或更高版本的Windows操作系统中,有一个名为”Print Spooler”的服务,该服务就是用于管理打印任务队列的,若该服务停止,则系统即使连接了打印机也不能进行打印输出。

图形设备上下文

    在了解了Windows图形子系统的基本原理后,我们可以开始了解Windows图形开发了,在Windows图形开发中有一个很重要的概念就是-图形设备上下文。

句柄

    对Windows编程有所了解的应该知道,WindowsAPI是一个个C语言样式的函数,应用程序访问大部分的操作系统资源是通过一种叫句柄的整数类型数据。例如程序访问文件,网络资源,图片,创建窗体等等都会事先调用API函数获得一个句柄,句柄可以理解成系统资源的唯一编号,应用程序应当好好保存这个句柄,妥善利用,不用时一定要使用API函数释放掉。

图形设备上下文句柄

    应用软件进行图形操作时也得使用API函数申请一个图形设备上下文句柄,以后所有的图形操作都是针对这个句柄来进行的,应用软件完成图形操作后一定要使用API释放这个图形设备上下文句柄。

    图形设备上下文是一种抽象概念,不限制到具体硬件,因此Windows内部可以在这个抽象概念上大做文章,图形设备上下文句柄可以指向显示器,也可以指向打印机或其他图形硬件,这个过程对应用软件是透明的,因此应用系统在此基础上能比较容易的实现所见即所得功能。可以做到一份图形操作代码,既可以向计算机屏幕输出图形,也可以控制打印机输出图形,这方便了图形开发。

软件设计模式

    这种抽象概念应用到不同的具体应用,是一种软件设计模式。比如在C#中有一个抽象类 System.IO.Stream , 它表示一个抽象的流的概念,而.NET框架中在这个抽象概念的流上面实现了各种具体的流,比如针对文件,HTTP资源,内存等等。应用软件只要编写代码将数据保存到抽象的流中,则同一份代码,可以同时将数据保存到本地文件,HTTP文件,FTP文件或内存中。这方便了程序的开发和扩展。

矢量图形和位图

概念

    图形开发中有两个重要的概念就是矢量图形和位图。

    所谓矢量图形,就是使用平面几何中的点线面等抽象概念来描述图形。而位图是采用大量的密集像素二维数组来描述图形的。

    对于计算机来说,矢量图复杂,但数据量小,可无级缩放;而位图显示过程简单,但数据量大,放大时显示效果差。

例子

    我们的电脑中存在很多矢量图和位图的例子。例如Flash是比较典型的矢量图软件,它生成的图形文件.swf文件小,放大时显示质量有保障;而Windows画图板是操作位图的,生成的图形文件.bmp文件大,放大时显示质量差。

    还比如Windows字体。Windows字体有位图字体和TrueType字体,位图字体是基于位图概念的,而TrueType字体是基于矢量图形的。目前大部分字体是TrueType字体,我们可以设置这种字体的样式,大小,使用TrueType字体的文本即使显示得非常大,其文本轮廓线条还是很清晰的。目前少数字体是位图字体,最常见的是Windows记事本默认使用的Fixedsys字体,这种字体放大显示时存在明显的锯齿。打印输出质量不高。

图形坐标系统

卡笛尔直角坐标

    描述和显示矢量图形时需要一个坐标系统,目前采用卡笛尔坐标,也就是具有X-Y轴的直角坐标。图形中每个图形元素都由若干个XY坐标值和宽度高度值来确定。比如一个点用一对XY值来确定位置,而一个线段用两个XY值来定位,而矩形用一个XY值和宽度高度值来定位。而圆或椭圆则用一个外切矩形来确定。

度量单位

    坐标系还需要指定度量单位,度量单位可以采用厘米,英寸。对于图形用户界面软件很多时候采用像素单位。

    厘米,英寸等是抽象的度量单位,图形采用这种抽象单位度量则是绝对准确的。而像素度量单位是和图形硬件相关的,一般情况下,显示器像素长度是96个像素一英寸,而打印机则是几百个甚至上千个像素一英寸。因此相同的图形,若采用像素大小,则在显示器中显示和实际打印的大小相差是很大的。在这种情况下应当采用抽象的厘米和英寸等度量单位,这样才能做到所见即所得。

    在.NET中已经考虑到了这种情况,枚举类型 System.Drawing.GraphicsUnit 就列出了一些标准的坐标度量单位。

坐标转换-Matrix(黑客帝国?)

    坐标系还可以转换,转换类型主要有平移,旋转和缩放。平移是指坐标原点(XY值都为0的点)上下左右移动,而坐标度量单位等属性不改变;旋转是指坐标系整体的以原点为中心,顺时针旋转一定的角度;而缩放则是将X轴或Y轴方向进行缩小或放大,X方向和Y方向的缩放可以是独立的。

    大家都知道电影《黑客帝国》,这个电影的英文名为Matrix.NET框架也提供了一个Matrix,它就是坐标转换对象,使用方便。它内部是一个3X3的矩阵,坐标系的平移旋转和缩放是通过一种矩阵运算来实现的。使用坐标转换对象,.NET程序可以很方便的实现某些特效,比如文本的垂直显示,文本的拉伸或压缩显示等等。

图形界面基本元素

    我们进行的大部分图形开发是操作矢量图形的。在平面几何中,矢量图形是有点线面组成的。因此一个个点,线或面就是矢量图形的基本元素。实际图形开发中,主要的图形界面基本元素有文本,直线段,矩形,椭圆(包括正圆),椭圆弧(包括圆弧),还有一些其他曲线。基本的绘图操作有绘制线条和填充区域。使用上述方法就能绘制出绝大多数的图形。

    在Windows图形用户界面中,使用最多的图形基本元素是文本和矩形。各种窗体,控间,其轮廓都是矩形。文本可以是单行,多行,可分为左对齐,居中对齐和右对齐等等。绘制文本和矩形是最简单最基本的图形操作。

用户界面事件

    大部分的图形化用户界面需要响应用户界面事件来实现互动式用户体验,用户界面事件主要包括窗体重绘事件,鼠标键盘事件,定时器事件,OLE拖拽事件等等,其中最重要的就是窗体重绘事件和鼠标键盘事件了。

    Windows底层使用Windows消息的方式向应用程序通知各种事件,而.NET框架封装了这些消息处理,并提供了一些可扩展的编程接口来方便进行事件响应编程。比如我们可以挂上控件的MouseDown事件,也可以重写控件的OnMouseDown方法来处理鼠标按键按下事件。

窗体重绘事件

    用户界面事件中必须处理的事件是窗体重绘事件。Windows是多任务操作系统,它允许显示器上同时显示多个窗体,于是窗体之间不可避免的发生覆盖。一个窗体的部分或全部可能被覆盖和重新显示。当控件由被遮盖到显示时,应用软件需要重新绘制控件的用户界面。

    如图所示,窗体2覆盖了窗体1,此时我的控件有一部分被覆盖了,当用户设置了窗体1靠前显示时,我的控件原先被窗体2覆盖的部分给显示出来了,此时形成了一个剪切矩形,程序需要重新绘制我的控件的用户界面,很显然,程序只需要绘制剪切矩形所包括的部分,其他的部分就不需要显示,这样我们就能使用这个剪切矩形来优化我们的程序,减少图形绘制工作量。

    我的控件不需要判断什么时候由于窗体重新显示时要重新绘制用户界面,Windows操作系统会判断这种情况,然后通过消息通知我的控件要重新绘制用户界面,而且在通知的时候就告诉了剪切矩形的位置和大小。

C#发现之旅第四讲 Windows图形开发入门

    在..NET平台上,.NET框架已经封装了底层的消息处理,并提供了Paint事件或OnPaint方法的编程接口。我们需要挂靠控件的Paint事件,或者重写OnPaint方法来重新绘制用户界面。在这个事件中系统提供两个参数,一个是图形绘制对象Graphics,另外一个是名为ClipRectangle的剪切矩形对象,也就是要重新绘制区域的边框。ClipRectangle是优化图形绘制操作的基础。

鼠标事件

    大部分情况下用户要求能使用鼠标操作来进行处理,此时图形软件必须响应用户的鼠标操作来进行某些处理,在C#图形软件开发中,我们需要响应控件的鼠标事件,我们需要挂靠控件的MouseDown或重写OnMouseDown方法来处理鼠标按键按下事件,使用MouseMove或重写OnMouseMove方法来处理鼠标移动事件,使用MouseUp事件或重写OnMouseUp方法来处理鼠标按键松开事件。

键盘事件

    用户也经常要求能使用键盘来进行操作,比如对于文本编辑器,用户需要使用键盘来输入大量的文本字符,移动光标等等。此时图形软件必须响应用户的键盘操作来进行某些处理,在C#图形软件开发中,我们需要响应控件的键盘事件,我们需要使用KeyDown或重写OnKeyDown方法来处理键盘按键按下事件,使用KeyUp事件或重写OnKeyUp方法来处理键盘按键松开事件,使用KeyPressOnKeyPress方法来处理键盘字符事件。

其他事件

    在C#中我们还可以处理其他的事件,比如我们在窗体中放置了一个定时器控件,则我们可以处理它的定时器事件来固定的每隔一段时间进行操作。我们从Windows资源管理器中拖拽一个文件到我们的程序中,我们可以响应控件的OLE拖拽事件来接受拖拽过来的文件的数据。

    通过各种各样的事件,我们就可以实现图形用户界面的各种动态操作特性。这样就维持了图形软件的正常运行,并提供了互动的用户体验。

小结

    本次课程主要是说明了Windows图形开发的基本原理,图形开发的一些理论知识。图形开发是一个很大的话题,其理论知识涉及很广泛,对此本次课程无法一一说明,在未来的培训中,将开始使用C#来实践图形开发,并在开发过程中补充说明其中涉及到的各种软件开发知识。

    大家若打算认真学习图形开发,可以发挥主观能动性,多多自我学习和相互学习。大家用惯了ASP.NET,对图形编程有些陌生,从下一次课程开始,我们将一起去发现C#图形开发。