第五课∶设备场景
一、什么是设备场景
关于设备场景,叫法颇多,有些书上说为设备环境、显示场景,更常见的叫做设备描述表或设备描述体。当然你爱怎么叫随你的便,我还是喜欢说为设备场景。
那么究竟什么是设备场景呢? 设备场景是一种Windows对象,而Windows则是一种图形环境,其图形系统令人难以自信地灵活和强大。而实质上,Widnows下的所有绘图都是通过设备场景进行的,而不是直接对窗口和设备本身进行。为了说明设备场景,很多书都拿一些现实生活中的现象来进行对照说明。其中,最常见的是把它比喻为一位画家在作画。我想大家都看过画家是如何画画的,最起码是在电影里或者是在道旁的广告牌上作画的画家。我们可以想象一下∶有个风景秀丽的白云山(是我瞎起的名)上,有位画家一只手拿着调色板,另一只手则拿着画笔,面对一个画板正在写风景画。有些书认为画家的调色板相当于设备场景,有些书则认为画板相当于设备场景,说法不一。鉴于这种情况,我认为还是直接去说明设备场景比较好。
作为Windows的对象,设备场景实际上是一种Windows内部的数据结构。就象POINTAPI数据结构具有x和y两个属性一样,设备场景同样具有着它自身的属性,只是属性比较多而已,如下表∶
设备场景属性
属 性 默 认 值
背景色(Background color) 白色(White)
背景模式(Background mode) 不透明(Opaque)
位图(Bitmap)无(None)
刷子(Brush)白色刷子(White brush)
刷子起点(Brush origin) 0,0
剪切区(Clipping region) 整个窗口或设备表面(Entire window or device surface)
调色板(Color palette) 默认调色板(Default palette)
画笔位置(Pen position) 0,0
绘图模式(Drawing mode) R2_COPYPEN
字体(Font) 系统字体
字间距(Intercharater spacing) 0
影射模式(Mapping mode) MM_TEXT
画笔(Pen) 黑色(Black)
多边形填充模式(Mapping Mode) ALTERNATE
伸缩模式(Stretching mode) BLACKONWHITE
文本色(Text color) 黑色(Black)
视口起点(Viewport origin) 0,0
视口范围(Viewport extents) 1,1
窗口起点(Window origin) 0,0
窗口范围(Window extents) 1,1
请你多看看这张表,对设备场景都有哪些属性,脑子里应当有个印象。事实上,设备场景的很多属性对应于VB中的Form、PictureBox、Text等窗体或控件的属性。比如,字体、背景色、绘图模式等等。可想而知,很多学VB的朋友尽管并不知道什么叫设备场景,但实质上都不知不觉地使用了设备场景。可以说,设备场景是Windows编程中最重要的概念之一。
对于设备场景,有些朋友可能一时不大好理解,这很自然,不用担心谁都是一样。不知对你能否作为一个帮助,我是把设备场景想象成一种配套的(包括画板、调色板、画笔、刷子等)的绘画工具。其中画板是最重要的,其他的东西都是为这个画板服务的。如过你创建了一个设备场景,就等于是你从百货商店买来了这一套绘画工具,从而具备了绘画的条件。但,你的房间总不是那么宽敞的。为了继续绘出别的画、继续购买新的绘画工具,无用的工具应当及时清理掉。因为设备场景本身是占用内存的。不要担心这会降低运行速度,对计算机来说创建一个设备场景,再删掉一个设备场景,那都是瞬息之间的事情,根本谈不上什么浪费时间,绝对不像跑一趟百货商店那么麻烦、费时。对于绘图,你应当认识的一点是,绘图并不是简单地指绘画,输出文本也是一种绘图过程。尽管如此,API函数中图形函数与文本函数大体都是各自各的。绘画和写文本都是在同样的设备场景中进行,这一点很重要。
我想,你大概还是没有理解好,不过没有关系,继续往下看好了。本节中请记住一点∶
Widnows下的所有绘图都是通过设备场景进行的。
二、如何从VB里使用设备场景
如何从VB里使用设备场景呢?VB的设计者们已经为我们想到了这一点,就象为了直接操纵窗体而提供了窗体句柄hWnd一样,为设备场景提供了hDC的句柄属性。很多API函数都是以hDC作为它的一个参数。如果控件没有提供hDC属性,你也可以用GetDC或
GetDCEx函数去获得,不用时就用ReleaseDC函数把它释放掉即可。不过这得需要控件具有hWnd属性。如果连hWnd属性也没有,那就没办法了,大概那根本不是绘图的地方。
按自己的需要也可以创建一个或多个设备场景,需要多少就创建多少。这可能是
CreateCompatibleDC和CreateDC函数的最拿手的好戏。设备场景可以同某一窗口关联,也可以以孤立的方式存在。所谓关联就是说,你在这个设备场景中绘图,内容将立即输出到关联的窗口,所谓孤立就是指尽管你在这个设备场景中绘出了图形,但它只存在于这个设备场景,而不显示在哪里。我们可以通过多个设备场景来对一个最终图形进行光栅运算,从而进行加工,最后把图象传送给已与窗体关联的设备场景,让它显示出来。被创建的设备场景,如果不再使用,应当删去。(这段描述,请参考附带的演示程序WindowDC.vbp。)
以下表格总结了用于获取和释放设备场景的API函数。
函 数 说 明
CreateCompatibleDC 创建一个与源DC兼容的内存设备场景。内存设备场景可看作一种对内存中设备的模拟。通过在设备中选进一幅位图,可创建与设备兼容的内存影响。
CreateDC 为指定的设备创建一个设备场景,它通常用于为打印机创建一个DC。
CreateIC 为指定的设备创建一个信息场景(IC)。IC类似于设备场景,只是所需系统开销更少,它可用来获取关于设备的信息,但不能作绘图操作。
DeleteDC 删除一个已经建立的设备场景。可用它释放CreateDC,CreateIC和CreateCompatibleDC 函数建立的设备场景。
GetDC,GetDCEx 为指定窗口获取一个设备场景。若窗口类使用专用DC,用该函数取回设备场景,否则它从Windows缓存中获取一个DC,用GetDCEx才能在窗口使用专用DC时获得一个缓存场景。
GetWindowDC 该函数与GetDC类似,只是取回的设备场景是针对窗口整个,而不是客户区。
ReleaseDC 释放用GetDC,GetDCEx和GetWindowDC获得的设备场景。若DC是一个专用设备场景,该函数无效。
WindowFromDC 判断与指定设备场景关联在一起的窗口句柄。
以下的演示程序是一个非常敾奶茢的程序。这个程序的目的是这样的∶我们要在Text控件中画一个圆。当然我估计没有人会选择Text控件来绘图。我总是喜欢用API做出一些歪门邪道的事情。以下是程序的源代码,你也可以直接启动教程附送的Program1.vbp演示程序。使用方法是,当我们点击Text控件时那里将出现了一个空心圆。
Option Explicit
Private Declare Function GetDC& Lib "user32" (ByVal hwnd As Long)
Private Declare Function Ellipse& Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
Private Declare Function ReleaseDC& Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long)
Private Sub Form_Load()
Text1.Text = ""
End Sub
Private Sub Text1_Click()
Dim TextDC As Long
TextDC = GetDC(Text1.hwnd) '获取设备场景句柄
Ellipse TextDC, 0, 0, 100, 100'画空心圆
ReleaseDC Text1.hwnd, TextDC'释放设备场景
End Sub
程序的工作原理是这样的。首先在Form_Load()事件中,我们用Text1.Text = ""代码来清除Text控件内的所有文本。接着,当我们点击Text控件时,程序在那里画一个圆,用的是API函数Ellipse(这个函数是下一课堂的内容)。Ellipse函数的功能很简单,在左上角为(x1,x2),右下角为(x2,y2)的矩形中画一个内切的椭圆。而Ellipse函数需要一个DC(设备场景句柄),但Text控件却没有提供hDC属性,没有办法只好用GetDC函数来获取∶TextDC = GetDC(Text1.hwnd)。然后做绘图操作,最后用ReleaseDC函数来把设备场景释放掉(关联设备场景,不能删除)。
如果我们把上述代码中的
TextDC = GetDC(Text1.hwnd)
Ellipse TextDC, 0, 0, 100, 100
改成
TextDC = GetDC(0)
Ellipse TextDC, 0, 0, 500, 500
会怎么样呢?不妨你试试看。学会了什么?还是直接告诉你吧∶整个屏幕的设备场景句柄总是等于0。
有意识吧?你也可以让Text控件输出一张图片(照片)。方法很简单。你可以使用Picture控件,在那里先装入一个图片,然后用API函数BitBlt把图片传送到Text控件就可以了,由你自己研究好了。
哈,现在感觉到设备场景真的存在了吧?呵呵,接着来吧!