=============《Windows 程序设计 第五版》读书笔记 || 第五章 图形基础 =============
一、设备内容信息
通过GetDeviceCaps函数可以获取设备内容信息,比如宽度、高度、色彩等。使用GetSystemMetrics函数也能获取设备内容中的一些信息。使用GetTextMetrics函数能获取设备内容中字体的相关信息。
二、混色和纯色
混色,用多种色彩组成的像素图案。纯色,单一的颜色,要在混色中取出某一色彩最接近的纯色,可用GetNearestColor函数。这么说吧,我们知道在PS中有一个调色盘,在调色盘中显示的是混色,但我们通常需要在调色盘中获取一种纯色,那么可以GetNearestColor函数来获取。
三、设备内容属性
刚开始我把设备内容信息与设备内容属性混为一谈,后来发现不是一回事儿。为了解释清楚这两个概念,我费了好大的劲儿。举个例子,在一个窗口类WNDCLASS中,包含了窗口样式(style)、窗口图标(hIcon)、窗口上显示的光标(hCursor)和窗口背景颜色(hbrBackgroud)等内容属性,每个属性所设置的值就是窗口的一部分内容。设备内容属性包括设备的背景颜色(Background Color)、文本颜色(Text Color)、字体(Font)、画笔(Pen)、画刷(Brush)、位图(Bitmap)等,除此之外还有一部分属性,不过在前面几章的学习中没有学习过。设备内容中的这些属性Windows都会设置默认值,比如我们在用TextOut输出文本时,其背景颜色属性值默认为白色。
这些默认的属性内容有时不能满足我们的需要,所以需要掌握设置设备内容属性值的方法,即设置设备内容信息。
1.设置文字背景颜色
使用TextOut输出文本时,默认的背景颜色属性是白色,如果要改变一个设备内容的背景颜色,需要使用SetBkColor函数,使用方法如下:
SetBkColor(hdc, RGB(255, 0, 0));
第一个参数是要修改背景颜色的设备内容句柄,第二个参数是要修改为了背景颜色,这里是设置为红色。
2.设置文字前景颜色
使用TextOut输出文本时,默认的前景颜色为黑色,如果要改变文字的前景颜色,需要使用SetTextColor函数,使用方法如下:
SetTextColor(hdc, RGB(255, 0, 0));
该函数的参数作用同SetBkColor。
3.其它更多
设备内容的属性太多,到目前为止,在前几章中接触过的只是一些文字相关的属性,除此之外设备内容中还包括了画笔/画刷/字体/位图等对象的属性,下面就来说说设置画笔/画刷的属性设置。
四、保存设备内容信息
使用SaveDC和RestoreDC可以保存和恢复设备内容信息,这看起来是个很简单的问题,但我却花了二三个小时才弄清楚,原因是起初我不清楚设备内容信息中都包含哪些内容,所以我才对设备内容信息和设备内容属性这两个概念分别作了解释。比如在用TextOut输出一段文字前,设置了文字的背景颜色属性和前景颜色属性,这称之为设备内容属性;将背景颜色设置为灰色,将前景颜色设置为黑色,这称之为设备内容信息。我们可以通过GetBkColor和GetTextColor两个函数来分别获取背景颜色和文本前景颜色这两设备内容属性的设备内容信息。可以写段代码来测试一下SaveDC和RestoreDC这两个函数的作用,主要是为了清楚用SaveDC会保存哪些信息。
以前这段代码进行了三次TextOut文字输出,第一次将背景颜色属性值为黑色,并用SaveDC来保存这个内容信息,接着第二次输出文字前,又将背景颜色属性值设为了白色,然后在第三次输出前用RestoreDC来恢复SaveDC之前的设备内容信息,最终的效果为第一次和第三次输出的文本背景颜色都为黑色。
小提示:要想明白SaveDC/RestoreDC的作用,就得分清设备内容信息和设备内容属性这两个概念,知道设备内容信息中都有些什么内容。
五、使用画笔
本来第五章是讲解如何绘图的,但在讲绘图前却首先花了整整一个小节来讲解设备内容相关的知识点,足以说明其重要性。接下来学习的内容包括在设备内容中如何使用画笔来画直线、矩形、椭圆形、椭圆线、扇形、圆角矩形和多边形等,简单的说就是在设备内容中使用画笔来画线。
1.Windows默认画笔
Windows提供了三种画笔:WHITE_PEN、BLACK_PEN和DC_PEN,默认使用的是BLACK_PEN画笔,可以用GetStockObject函数来选择一种画笔,GetStockObjectb会返回一个画笔句柄HPEN。值得一提的是,使用GetStockObject不仅可以选择画笔,还可以选择画刷,字体等,使用不同的参数可返回不同的句柄类型,该函数的使用方法如下:
画笔选好了,在设备内容中就可以使用选择的画笔来画图么?还不能。因为现在虽然选择了非默认的画笔,但设备内容还不知道作了改变,还需要将自定义的画笔选入设备内容中,也可以说成将画笔与设备内容进行关联,这要用到SelectObject函数:
由此一来,我们就知道整个绘图流程,先选择一个画笔,接着告知设备内容使用所选择的画笔,再使用画线函数来绘图。
小提示:WHITE_PEN是一个白色画笔,BLACK_PEN是一个黑色画笔,DC_PEN默认也是一个白色画笔,不过可以通过SetDCPenColor函数来改变DC_PEN的颜色。这三种画笔都只能画实线,但以后我们可以建立自己的画笔来画点线和虚线。
2.建立/选择/删除自定义的画笔
使用Windows提供的三种画笔虽然可以画出不同颜色的线形,但却限制了线形的样式和宽度,比如要想画一条粗的虚线,用Windows提供的三种画笔就办不到,这时我们需要使用CreatePen和CreatePenIndirect来建立自定义逻辑画笔。这下又多了个概念,什么是逻辑画笔?可以这样理解,逻辑画笔不是为某一个特定的设备内容而产生的,不同的设备内容也可以使用相同的逻辑画笔,所以在CreatePen和CreatePenIndirect函数中不用指定设备内容句柄,而是需要使用SelectObject函数来选择设备内容使用的画笔。
CreatePen函数的语法如下:
第一个参数是设置画笔样式,是画实线/点线还是虚线
第二个参数是设置线条宽度
第三个参数是设置线条颜色
CreatePenIndirect函数的语法如下:
CreatePen与CreatePenIndirect函数的不同之处是CreatePen是在参数中直接进行设置画笔样式/宽度和颜色,而CreatePenIndirect是将这三个参数放入一个LOGPEN结构体中。
同使用Windows提供的画笔一样,在建立画笔后,还需要使用SelectObject函数来选择新建的画笔,如果觉得使用两句代码来实现画笔的建立和选择操作麻烦,可以将这两个操作缩到一句代码中:
SelectObject(hdc, CreatePen(PS_SOLID, 1, 0));
建立画笔需要分配内存,所以当不用建立的画笔后,我们需要删除画笔以释放内存。其使用语法如下:
DeleteObject(hPen);
DeleteObject参数中是一个画笔句柄,但我们将画笔的建立和选择缩写到一句代码中时,没有保存画笔句柄,咋整?不用担心,SelectObject会返回上一次使用的画笔句柄。
DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN))); //选择一个新画笔,并返回上一次使用的画笔
书中对CreatePen函数的使用方法作了详细介绍,但CreatePenIndirect函数只是一笔带过,下面说说CreatePenIndirect函数的使用方法。
CreatePenIndirect函数只有一个参数,这个参数是一个结构体,在这个结构体中包含了画笔样式/宽度和颜色的设置,看个示例代码就一目了然了(在MSDN中查看LOGPEN结构体的成员就知道如何如何设置LOGPEN成员的值):
在建立画笔时需要设置画笔样式/宽度和颜色,以后若有需要我们也可以提取这个画笔的样式/宽度和颜色,可以使用GetObject函数来实现,比如要提取一个名为hPen的画笔的画笔样式/宽度和颜色,可以用以下代码:
GetObject(hPen, sizeof(LOGPEN), &logpen);
该函数可以将hPen中的画笔样式/宽度和颜色存入logpen结构体中。
建立画笔后,需要为设备内容选择这个画笔,那么我们如何知道设备内容使用什么样的画笔呢?可以用GetCurrentObject来获取设备内容中的画笔,并返回该画笔的句柄:
hPen = GetCurrentObject(hdc, OBJ_PEN);
其实GetObject和GetCurrentObject函数的作用大同小异,前者是返回画笔的描述(样式/宽度和颜色),后者是返回画笔句柄,而在画笔句柄中就包含了画笔的描述。其不同之处在于,GetObject是在画笔中提取信息,而GetCurrentObject是在设备内容中提取信息。
3.画笔空隙设置
什么是画笔的空隙,这是在点线和虚线中才有的描述,而实线是没有空隙的。比如虚线是由多个短的实线组成,而在这些短的实线间会有一个空隙,我们可以为这些空隙设置背景颜色,也可以修改背景颜色模式阻止填入空隙。
SetBkColor(hdc, RGB(255, 255, 255)); //设置空隙背景颜色
SetBkMode(hdc, TRANSPARENT); //修改背景模式,阴止填入空隙
如果我们画一个虚线,将画笔颜色设为黑色,接着用SetBkColor设置空隙背景颜色也为黑色,那画出的是什么线呢?答案是实线。
4.绘图方式
对于绘图方式的理解,我算不上是稀里糊涂,但要让我解释还真有些困难。简单的说,我们设置不同的绘图方式,Windows会根据画笔颜色和设备内容背景颜色的不同来调整显示出不同的颜色。而Windows是怎么调整的呢,用的是布尔运算。照搬书上的两句话:图素间的位布尔运算叫做“位映像运算”,简称“ROP”。由于画一条直线只涉及两种图素(画笔和目标),因此这种布尔运算又称为“二元位映像运算”,简称“ROP2”。不太明白这两句话,也不太了解色彩,比如什么颜色加上什么颜色会变为别一种什么颜色。呵呵~算了,需要时再深入学习吧!设置绘图方式的函数为SetROP2,到目前为止只清楚两种绘图方式的作用:
SetROP2(hdc, R2_BLACK); //不管画笔和设备内容背景是什么颜色,画出的线都是黑色
SetROP2(hdc, R2_WHITE); //不管画笔和设备内容背景是什么颜色,画出的线都是白色
六、使用画刷
使用画笔可以画线条,但使用画刷就可以画图形了。在这一章中,介绍了Windows的七个画图形的函数:
Rectangle 画直角矩形
Ellipse 画椭圆
RoundRect 画圆角矩形
Chord //画弧
Pie //画饼图
Polygon //画多边形
PolyPolygon //画多个多边形
使用画笔画图形只能画出边框,而要想给图形设置填充色,还得使用画刷。Windows定义了六种画刷:WHITE_BRUSH、LTGRAY_BRUSH 、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH、NULL_BRUSH。这六种画刷定义了不同的填充颜色。画刷的建立、选择和删除与画笔相同,我们可以画几个图形来认识一下这几种画刷。
例如在一个灰色背景和窗口上,画一个边框为红色,填充色为深灰色的矩形,那就需要先用画笔设置边框颜色,接着用画刷设置填充颜色,然后再用Rectangle函数来画矩形,下面是代码:
小提示:Windows默认的画笔为BLACK_PEN,Windows默认的画刷为WHITE_BRUSH,如果我们取消第4行和第6行代码的话,那么这个矩形的填充颜色就是白色的。Windows窗口显示区域的背景颜色可以使用画刷来改变。
如果对Windows提供的六种画刷不能满足需要,那就得建立自己的画笔了,建立画刷有三个函数:
CreateSolidBrush(crColor);
CreateHatchBrush(iHatchStyle, crColor);
CreateBrushIndirect(&logbrush);