-----路过的朋友,若发现错误或有好的建议,欢迎在下面留言,谢谢!-----
设备描述表还真是十分重要,以至于我们在这里还要再学习它。这节内容比较少,相信你很快就应该能看完。Let’go!
获取设备描述表句柄
复习:当你想在一个图形输出设备(诸如屏幕或者打印机)上绘图时,你首先必须获得一个设备描述表(或者DC)的句柄。将句柄传回给程序时,Windows就给了你使用设备的权限。然后你在GDI函数中将这个句柄作为一个参数,向Windows标识你想在其上进行绘图的设备。如果在处理一个消息时取得了设备描述表句柄,应该在退出窗口函数之前释放它(或者删除它)。一旦释放了句柄,它就不再有效了。
Windows提供了几种取得设备描述表句柄的方法,如下。
方法一:
这是获取并释放设备描述表句柄最常用的方法,即在处理WM_PAINT消息时使用BeginPaint和EndPaint函数。这两个函数需要程序的窗口句柄和PAINTSTRUCT结构的变量的地址为参数。Windows程序员通常把这一结构变量命名为ps并且在窗口过程中定义它:
PAINTSTRUCT ps ;
在处理WM_PAINT消息时,窗口过程首先调用BeginPaint。一般在BeginPaint函数的调用中,如果客户区的无效区域的背景还未被擦除,则由Windows来擦除。(它使用已注册的窗口类WNDCLASS结构的hbrBackground成员变量中指定的画刷来擦除背景,上回的注释1我们提过)
BeginPaint调用使整个客户区有效,并且返回一个设备描述表句柄,这一返回值通常被保存在叫做hdc的变量中。该函数也填入ps结构的字段(可以回忆一下上一回的注释1)。
设备描述表句柄在窗口过程中的定义如下:
HDC hdc ;//定义设备描述表句柄变量
然后,程序就可以使用需要设备描述表句柄的TextOut等GDI函数。在窗口的客户区显示文字和图形需要设备描述表句柄,但是从BeginPaint返回的设备描述表句柄不能在客户区域之外绘图。调用EndPaint即可释放设备描述表句柄。
一般地,处理WM_PAINT消息的形式如下:
caseWM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
[other program lines]
EndPaint (hwnd, &ps) ;
return 0 ;
我们再来强调一下吧(别怪我啰嗦):BeginPaint调用使整个客户区有效(阻止WM_PAINT消息一直发送,见附录),填充ps结构的字段,返回的设备描述表句柄。使用这个句柄只能在ps结构中的rcPaint字段规定的区域内绘图。EndPaint调用可释放设备描述表句柄。两个函数必须成对使用,一般只用在处理WM_PAINT消息中。
Windows程序在处理非WM_PAINT消息时还可以用以下方法获得设备描述表句柄,当然以下函数调用不会使客户区中的无效区域变成有效。
方法二:
hdc = GetDC (hwnd) ;
[other program lines]
ReleaseDC (hwnd, hdc) ;
GetDC函数调用后会返回hwnd参数所指定的窗口的客户区所对应的设备描述表句柄。可见GetDC调用与BeginPaint的基本区别是,利用从GetDC返回的句柄可以在整个客户区上绘图。如果hwnd参数设置为NULL,那么函数会返回整个桌面的设备描述表句柄。当不再需要该设备环境时,需要调用ReleaseDC函数释放设备描述表。
方法三:
hdc = GetWindowDC (hwnd) ;
[other program lines]
ReleaseDC (hwnd, hdc) ;
GetWindowDC返回可以在整个窗口(包括客户区部分和标题栏、菜单、滚动条、框架等非客户区部分)绘图的设备描述表句柄,不过此函数很少使用。当不再需要该设备描述表时,需要调用ReleaseDC函数释放设备描述表。
方法四:
hdc =CreateDC (lpszDriver, lpszDevice, lpszOutput, lpData) ;
[other program lines]
DeleteDC (hdc) ;
BeginPaint、GetDC和GetWindowDC获得的设备内容都与显示器上的某个特定窗口(即hwnd)相关。CreateDC是取得设备描述表句柄一个更通用的函数,它甚至可以获取非显示器输出设备描述表句柄。当不再需要该设备描述表时只可调用DeleteDC函数删除它。
当然,获得设备描述表的函数还有很多,我们就先简单介绍到这儿,其他类似的函数我们以后遇到再说。
设备描述表的属性——我们上回提到过哦
设备描述表中包含许多确定GDI函数如何在设备上工作的当前“属性”,这些属性允许传递给GDI函数的参数只包含起始坐标或者尺寸信息,而不必包含Windows在设备上显示对象时需要的所有其它信息。例如,上回我们调用TextOut时,我们只需要在函数中给出设备描述表句柄、起始坐标、文字和文字的长度。而不必指定字体、文字颜色、文字后面的背景色彩以及字符间距,因为这些属性都是设备描述表的一部分。当你想改变这些属性之一时,您调用一个可以改变设备描述表中属性的函数(例如把文字颜色设置成红色),以后针对该设备描述表的TextOut调用
就可以使用改变后的属性了(例如可以输出红色字体)。
我在此列出如下表,方便大家查阅。
属性
|
默认值
|
相关函数
|
背景色
|
WHITE
|
GetBkColor
|
SetBkColor
|
背景模式
|
OPAQUE
|
GetBkMode
|
SetBkMode
|
位图
|
NONE
|
CreateBitMap
|
CreateBitMapIndirect
|
CreateCompatibleBitmap
|
SelectObject
|
画刷
|
WHITE_BRUSH
|
CreateBrushIndirect
|
CreateDIBPatternBrush
|
CreateHatchBrush
|
CreatePatternBrush
|
CreateSolidBrush
|
SelectObject
|
画刷起始位置
|
(0,0)
|
GetBrushOrg
|
SetBrushOrg
|
UnrealizeObject
|
剪裁域
|
DISPLAY SURFACE
|
ExcludeClipRect
|
IntersetClipRect
|
OffsetClipRgn
|
SelectClipPath
|
SelectObject
|
SelectClipRgn
|
颜色调色板
|
DEFAULT_PALETTE
|
CreatePalette
|
RealizePatte
|
SelectPalette
|
绘图方式
|
R2_COPYPEN
|
GetROP2
|
SetROP2
|
字体
|
SYSTEM_FONT
|
CreateFont
|
CreateFontIndirect
|
SelectObject
|
字符间距
|
0
|
GetTextCharacterExtra
|
SetTextCharacterExtra
|
映射方式
|
MM_TEXT
|
GetMapMode
|
SetMapMode
|
画笔
|
BLACK_PEN
|
CreatePen
|
CreatePenIndirect
|
SelectObject
|
多边形填充方式
|
ALTERNATE
|
GetPolyFillMode
|
SetPolyFileMode
|
缩放模式
|
BLACKONWHITE
|
SetStretchBltMode
|
GetStretchBltMode
|
文本颜色
|
BLACK
|
GetTextColor
|
SetTextColor
|
视图范围
|
(1,1)
|
GetViewportExtEx
|
SetViewportExtEx
|
ScaleViewportExtEx
|
视图原点
|
(0,0)
|
GetViewportOrgEx
|
|
|
SetViewportOrgEx
|
窗口范围
|
(1,1)
|
GetWindowExtEx
|
SetWindowExtEx
|
ScaleWindowExtEx
|
窗口原点
|
(0,0)
|
GetWindowOrgEx
|
OffsetWindowOrgEx
|
SetWindowOrgEx
|
一般以Get开头的函数作用是获取该属性值,一般以Set开头的函数作用是设置该属性值,若有不太清楚的函数,你就自己动手查吧。
保存设备描述表
通常,在你调用GetDC或BeginPaint时,Windows用默认值建立一个新的设备描述表,你对属性所做的一切改变在设备描述表调用ReleaseDC或EndPaint释放时,都会丢失。如果你的程序需要使用非默认的设备描述表属性,则你必须在每次取得设备描述表句柄时初始化设备内容:
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
[initialize device context attributes]
[paint client area of windows]
EndPaint (hwnd, &ps) ;
return 0 ;
虽然在通常情况下这种方法已经很令人满意了,但是你还可能想要在释放设备描述表之后,仍然保存程序中对设备描述表属性所做的改变,以便在下一次调用GetDC和BeginPaint时它们仍然能够起作用。为此,可在设计窗口类时,将CS_OWNDC标志包含为窗口类的一部分:
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC ;
现在,基于这个窗口类所创建的每个窗口都将拥有自己的设备描述表,它一直存在,直到窗口被删除。如果使用了CS_OWNDC风格,就只需初始化设备描述表一次,可以在处理WM_CREATE消息处理期间完成这一操作:
case WM_CREATE:
hdc = GetDC (hwnd) ;
[initialize device context attributes]
ReleaseDC (hwnd, hdc) ;
这些属性在改变之前一直有效。
CS_OWNDC风格只影响GetDC和BeginPaint获得的设备内容,不影响其它函数获得的设备描述表。使用了CS_OWNDC,你仍然应该在退出窗口过程之前释放设备描述表。
某些情况下,你可能想改变某些设备描述表属性,用改变后的属性进行绘图,然后恢复原来的设备描述表属性。要简化这一过程,可以通过如下调用来保存设备描述表的状态:
int idSaved = SaveDC (hdc) ;
现在,可以改变一些属性,在想要回到调用SaveDC前存在的设备内容时,调用:
RestoreDC (hdc, idSaved) ;
你可以在调用RestoreDC之前调用SaveDC数次。
大多数程序写作者以不同的方式使用SaveDC和RestoreDC。然而,更像汇编语言中的PUSH和POP指令,当你调用SaveDC时,可以不需要保存返回值:
SaveDC (hdc) ;
然后,你可以更改某些属性并再次调用SaveDC。要将设备内容恢复到一个已经保存的状态,调用:
RestoreDC (hdc, -1) ;
这就将设备描述表恢复到最近由SaveDC函数保存的状态中。
附录
小技巧:
在处理WM_PAINT消息时,为了在更新的矩形外绘图,可以在调用BeginPaint之前使用如下函数:
InvalidateRect (hwnd, NULL, TRUE) ;
它使整个显示区域变为无效,并擦除背景。但是,如果最后一个参数等于FALSE,则不擦除背景,原有的东西将保留在原处。
通常这是Windows程序在无论何时收到WM_PAINT消息而不考虑rcPaint结构的情况下简单地重画整个客户区最方便的方法。例如,如果在客户区的显示输出中包括了一个圆,但是只有圆的一部分落到了无效矩形中,它就仅绘制圆在无效矩形中的部分。这对于画整个圆来说是无意义的。注意:使用从BeginPaint返回的设备描述表句柄时,Windows不会绘制rcPaint矩形外的任何部分。在BeginPaint调用之前使用上面那个函数,可使rcPaint结构中的无效矩形为整个客户区,就不愁绘制圆了。
在处理WM_PAINT消息时,必须成对地调用BeginPaint和EndPaint。如果窗口过程不处理WM_PAINT消息,则它必须将WM_PAINT消息传递给Windows中DefWindowProc(默认窗口过程)。DefWindowProc以下列代码处理WM_PAINT消息:
case WM_PAINT:
BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
这两个BeginPaint和EndPaint调用之间中没有任何语句,仅仅使先前无效区域变为有效。但以下方法是错误的:
case WM_PAINT:
return 0 ;// WRONG !!!
Windows将一个WM_PAINT消息放到消息队列中,是因为客户区的一部分无效。如果不调用BeginPaint和EndPaint(或者ValidateRect),则Windows不会使该区域变为有效。若一直保持无效,Windows将会再发送另一个WM_PAINT消息,且一直发送下去。
分享到:
相关推荐
### Windows编程(第6版) #### 书籍概览与作者介绍 《Windows编程》第六版是Charles Petzold的经典著作,专注于编写适用于Windows 8的Metro风格应用。本书由Microsoft Press出版,是一本针对消费者预览版的电子书...
《Windows核心编程》是Windows平台开发领域的一部经典著作,主要涵盖了Windows操作系统内核的各个方面,为开发者提供了深入理解Windows系统编程的详细指南。这本书第五版的PPT内容可能包括了以下几个关键知识点: 1...
| CS_OWNDC | 为该类中每个窗口分配了一个单值的设备描述表 | | CS_DBLCLKS | 当用户双击鼠标时向窗体程序发送一个双击的信息,同时光标位于该类的窗口之中 | | CS_PARENTDC | 在母窗口中建立一个剪区,使得子窗口...
7. **用户界面设计**:创建美观且易用的用户界面是Windows编程的一部分,包括控件的使用、对话框的设计、菜单和快捷键的配置等。 8. **系统调用**:深入学习系统调用,如NtCreateFile、NtMapViewOfSection等,能够...
第6章 磁盘过滤 127 6.1 磁盘过滤驱动的概念 128 6.1.1 设备过滤和类过滤 128 6.1.2 磁盘设备和磁盘卷设备过滤驱动 128 6.1.3 注册表和磁盘卷设备过滤驱动 129 6.2 具有还原功能的磁盘卷过滤驱动 129 6.2.1 简介 129...
《Windows编程技术——图形程序的编程基础》 Windows图形设备接口(Graphics Device Interface,简称GDI)是Windows操作系统中用于处理图形输出的核心组件。它提供了一系列的函数、结构和数据类型,使得程序员能够...
根据给定文件信息,这里是一份关于书籍《Windows游戏编程》的知识点说明。首先,这本书的作者是罗林,由华南理工大学出版社出版。该书的ISBN为***,出版时间是2017年7月,是第一版次,属于平装本,开本为32开,并...
第6章 磁盘过滤 127 6.1 磁盘过滤驱动的概念 128 6.1.1 设备过滤和类过滤 128 6.1.2 磁盘设备和磁盘卷设备过滤驱动 128 6.1.3 注册表和磁盘卷设备过滤驱动 129 6.2 具有还原功能的磁盘卷过滤驱动 129 6.2.1 简介 129...
第6章 进程、线程和模块 150 6.1 基本概念 150 6.1.1 应用程序与进程 150 6.1.2 控制台应用程序与图形用户界面应用程序 151 6.1.3 动态链接库、模块 151 6.1.4 线程、纤程与作业 152 6.1.5 权限与...
通过阅读《Windows系统编程 第三版》,开发者不仅可以掌握Windows编程的基本技能,还能了解到系统的底层运作机制,从而能够编写出更高效、稳定的应用程序。这本书对于想要提升自己Windows开发能力的程序员来说,无疑...
第6章 磁盘过滤 127 6.1 磁盘过滤驱动的概念 128 6.1.1 设备过滤和类过滤 128 6.1.2 磁盘设备和磁盘卷设备过滤驱动 128 6.1.3 注册表和磁盘卷设备过滤驱动 129 6.2 具有还原功能的磁盘卷过滤驱动 129 6.2.1 简介 129...
【标题】"三菱FX,Windows中文编程软件"指的是在Windows操作系统环境下,专为三菱FX系列PLC设计的中文编程工具。三菱FX系列是三菱电机推出的一系列小型可编程控制器(PLC),广泛应用于自动化设备、生产线等控制领域...
第6章 进程、线程和模块 150 6.1 基本概念 150 6.1.1 应用程序与进程 150 6.1.2 控制台应用程序与图形用户界面应用程序 151 6.1.3 动态链接库、模块 151 6.1.4 线程、纤程与作业 152 6.1.5 权限与...
《寒江独钓:Windows内核安全编程》是针对Windows操作系统内核安全编程的一部重要教程,本章节主要聚焦在入门基础知识与安全编程的核心概念。Windows内核是系统的核心部分,它负责管理硬件资源、调度进程以及提供系统...
第6章 磁盘过滤 127 6.1 磁盘过滤驱动的概念 128 6.1.1 设备过滤和类过滤 128 6.1.2 磁盘设备和磁盘卷设备过滤驱动 128 6.1.3 注册表和磁盘卷设备过滤驱动 129 6.2 具有还原功能的磁盘卷过滤驱动 129 6.2.1 简介 129...
《Windows核心编程》第四版是一本深入探讨Windows操作系统内核的权威著作,旨在帮助开发者理解Windows系统的底层工作原理,从而能够编写出更高效、更稳定的系统级程序。这本书的高清电子版结合光盘源码,为读者提供...
第6章 磁盘过滤 127 6.1 磁盘过滤驱动的概念 128 6.1.1 设备过滤和类过滤 128 6.1.2 磁盘设备和磁盘卷设备过滤驱动 128 6.1.3 注册表和磁盘卷设备过滤驱动 129 6.2 具有还原功能的磁盘卷过滤驱动 129 6.2.1 简介 129...