Windows程序设计:GDI结构和设备内容


目录:
1.GDI的结构
2.设备内容
         取得设备内容句柄
         取得设备内容信息
         关于色彩
         设备内容属性
         保存设备内容

1.GDI的结构

从程序写作者的观点来看,GDI由几百个函数呼叫和一些相关的数据型态、宏和结构组成。

GDI函数呼叫分类
1.取得(或者建立)和释放(或者清除)设备内容的函数
2.取得有关设备内容信息的函数
3.绘图函数
4.设定和取得设备内容参数的函数
5.使用GDI对象的函数

GDI基本图形
1.直线和曲线:线条是所有向量图形绘制系统的基础。GDI支持直线、矩形、椭圆(包括椭圆的子集,也就是我们所说的「圆」)、椭圆圆周上的部分曲线即所谓的「弧」以及贝塞尔曲线。所有更复杂的曲线可由折线(polyline)代替,折线通过一组非常短的直线来定义一条曲线。线条用设备内容中选中的目前画笔绘制。
2.填入区域:当一系列直线或者曲线封闭了一个区域时,该区域可以使用目前GDI画刷对象进行填图。这个画刷可以是实心色彩、图案(可以是一系列的水平、垂直或者对角标记)或者是在区域内垂直或者水平重复的位图图像。
3.位图:是位的矩形数组,这些位对应于显示设备上的图素,它们是位映像图形的基础工具。位图通常用于在视讯显示器或者打印机上显示复杂(一般都是真实的)图像。位图还可以用于显示必须快速绘制的小图像(诸如图标、鼠标光标以及在应用工具条中出现的按钮等)。GDI支持两种型态的位图-旧式的(虽然还非常有用)「设备相关」位图,是GDI对象;和新的(如Windows 3.0的)「设备无关」位图(或者DIB),可以储存在磁盘文件中。
4.文字

其他部分:
1.映象模式和变换:虽然内定以图素为单位进行绘图,但是您并非局限于此。GDI映像模式允许您以英寸(或者甚至以几分之一英寸)、毫米或者任何您想使用的单位来绘图(Windows NT还支持传统的以三乘三矩阵表示的「坐标变换」, 这允许倾斜和旋转图形对象。
2.Metafile:以二进制形式储存的GDI命令集合。Metafile主要用于通过剪贴板传输向量图形。
3.绘图区域:是形状任意的复杂区域,通常定义为较简单的绘图区域组合。在GDI内部,绘图区域除了储存为最初用来定义绘图区域的线条组合以外,还以一系列扫描线的形式储存。您可以将绘图区域用于绘制轮廓、填入图形和剪裁。
4.路径:GDI内部储存的直线和曲线的集合。路径可以用于绘图、填入图形和剪裁,还可以转换为绘图区域。
5.剪裁:绘图可以限制在显示区域的某一部分中,这就是所谓的剪裁。剪裁区域是不是矩形都可以,剪裁通常是通过区域或者路径来定义的。
6.调色盘:自订调色盘通常限于显示256色的显示器。Windows仅保留这些色彩之中的20种以供系统使用,您可以改变其它236种色彩,以准确显示按位图形式储存的真实图像
7.打印

2.设备内容

取得设备内容句柄

最常用的取得设备内容的方法是,在处理WM_PAINT消息时,使用BeginPaint和EndPaint呼叫:

hdc=BeginPaint(hwnd, &ps);
//其他行程序
EndPaint(hwnd, &ps);

变量ps是型态为PAINTSTRUCT的结构,该结构的hdc字段是BeginPaint传回的设备内容句柄。 PAINTSTRUCT结构又包含一个名为rcPaint的RECT(矩形)结构,rcPaint定义一个包围窗口显示区域无效范围的矩形。使用从BeginPaint获得的设备内容句柄,只能在这个区域内绘图。BeginPaint呼叫使该区域有效。

在处理非WM_PAINT消息时,使用GetDC和ReleaseDC取得设备内容句柄:

hdc = GetDC(hwnd);
//其他行内容
ReleaseDC(hwnd, hdc);
这个设备内容适用于窗口句柄为hwnd的显示区域。这些呼叫与BeginPaint和EndPaint的组合之间的基本区别是,利用从GetDC传回的句柄可以在整个显示区域上绘图。当然, GetDC和ReleaseDC不使显示区域中任何可能的无效区域变成有效。

Windows程序还可以取得适用于整个窗口(而不仅限于窗口的显示区域)的设备内容句柄:

hdc = GetWindowDC(hwnd);
//其他行内容
ReleaseDC(hwnd, hdc);

这个设备内容除了显示区域之外,还包括窗口的标题列、菜单、滚动条和框架(frame)。GetWindowDC函数很少使用,如果想尝试用一用它,则必须拦截处理WM_NCPAINT消息,Windows使用该消息在窗口的非显示区域上绘图。

BeginPaint、GetDC和GetWindowDC获得的设备内容都与视讯显示器上的某个特定窗口相关。取得设备内容句柄的另一个更通用的函数是CreateDC:

hdc = CreateDC(pszDriver, pszDevice, pszOutput, pData);
//其他行内容
DeleteDC(hdc);

CreateDC声明如下:
HDC CreateDC(
        LPCTSTR lpszDriver,      //指向字符串的指针,该字符串是一个驱动程序名
  __in  LPCTSTR lpszDevice,      //指向字符串的指针,该字符串指定了正在使用的特定输出设备的名字
        LPCTSTR lpszOutput,      //该参数在32位应用中被忽略,并置为Null,提供它是为了与16位应用程序兼容
  __in  const DEVMODE *lpInitData//指向包含设备驱动程序的设备指定初始化数据的DEVMODE结构的指针 
);//返回值:成功,返回值是特定设备的设备上下文环境的句柄;失败,返回值为Null

例如,您可以通过下面的呼叫来取得整个屏幕的设备内容句柄:
hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);

您还可以使用CreateIC来取得一个「信息内容」的句柄,其参数与CreateDC函数相同,例如:

hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);

不过,您不能用这个信息内容句柄往设备上写东西。

使用位图时,取得一个「内存设备内容」有时是有用的:

hdcMem = CreateCompatibleDC(hdc);
//其它行程序,函数CreateCompatibleDC创建一个与指定设备兼容的内存设备上下文环境
DeleteDC(hdcMem);

您可以将位图选进内存设备内容,然后使用GDI函数在位图上绘画。

metafile是一些GDI呼叫的集合,以二进制形式编码。您可以通过取得metafile设备内容来建立metafile:

hdcMeta = CreateMetaFile(pszFilename);
//其它行程序
hmf = CloseMetaFile(hdcMeta);

在metafile设备内容有效期间,任何用hdcMeta所做的GDI呼叫都变成metafile的一部分而不会显示。在呼叫CloseMetaFile之后,设备内容句柄变为无效,函数传回一个指向metafile(hmf)的句柄。

取得设备内容信息

一个设备内容通常是指一个实际显示设备,如视讯显示器和打印机。通常,您需要取得有关该设备的信息,包括显示器的大小(单位为图素或者实际长度单位)和色彩显示能力。您可以通过呼叫GetDeviceCaps(「取得设备功能」)函数来取得这些信息:

iValue = GetDeviceCaps(hdc, iIndex);

参数iIndex取值为WINGDI.H表头文件中定义的29个标识符之一。例如,iIndex为HORZRES时将使GetDeviceCaps传回设备的宽度(单位为图素);iIndex为VERTRES时将让GetDeviceCaps传回设备的高度(单位为图素)。如果hdc是打印机设备内容的句柄,则GetDeviceCaps传回打印机显示区域的高度和宽度,它们也是以图素为单位的。

还可以使用GetDeviceCaps来确定设备处理不同型态图形的能力,这对于视讯显示器并不很重要,但是对于打印设备却是非常重要。例如,大多数绘图机不能画位图图像,GetDeviceCaps就可以将这一情况告诉您。

下面的例子以一个视讯显示器的设备内容为参数,用GetDeviceCaps函数中获得部分信息:

#include <windows.h>
#define NUMLINES ((int) (sizeof devcaps / sizeof devcaps [0]))
 
struct
{
     int     iIndex ;
     TCHAR * szLabel ;
     TCHAR * szDesc ;
}
devcaps [] =
{
     HORZSIZE,      TEXT ("HORZSIZE"),     TEXT ("Width in millimeters:"),
     VERTSIZE,      TEXT ("VERTSIZE"),     TEXT ("Height in millimeters:"),
     HORZRES,       TEXT ("HORZRES"),      TEXT ("Width in pixels:"),
     VERTRES,       TEXT ("VERTRES"),      TEXT ("Height in raster lines:"),
     BITSPIXEL,     TEXT ("BITSPIXEL"),    TEXT ("Color bits per pixel:"),
     PLANES,        TEXT ("PLANES"),       TEXT ("Number of color planes:"),
     NUMBRUSHES,    TEXT ("NUMBRUSHES"),   TEXT ("Number of device brushes:"),
     NUMPENS,       TEXT ("NUMPENS"),      TEXT ("Number of device pens:"),
     NUMMARKERS,    TEXT ("NUMMARKERS"),   TEXT ("Number of device markers:"),
     NUMFONTS,      TEXT ("NUMFONTS"),     TEXT ("Number of device fonts:"),
     NUMCOLORS,     TEXT ("NUMCOLORS"),    TEXT ("Number of device colors:"),
     PDEVICESIZE,   TEXT ("PDEVICESIZE"),  TEXT ("Size of device structure:"),
     ASPECTX,       TEXT ("ASPECTX"),      TEXT ("Relative width of pixel:"),
     ASPECTY,       TEXT ("ASPECTY"),      TEXT ("Relative height of pixel:"),
     ASPECTXY,      TEXT ("ASPECTXY"),     TEXT ("Relative diagonal of pixel:"),
     LOGPIXELSX,    TEXT ("LOGPIXELSX"),   TEXT ("Horizontal dots per inch:"),
     LOGPIXELSY,    TEXT ("LOGPIXELSY"),   TEXT ("Vertical dots per inch:"),
     SIZEPALETTE,   TEXT ("SIZEPALETTE"),  TEXT ("Number of palette entries:"),
     NUMRESERVED,   TEXT ("NUMRESERVED"),  TEXT ("Reserved palette entries:"),
     COLORRES,      TEXT ("COLORRES"),     TEXT ("Actual color resolution:")
} ;
 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("DevCaps1") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
 
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
 
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
 
     hwnd = CreateWindow (szAppName, TEXT ("Device Capabilities"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
 
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
 
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static int  cxChar, cxCaps, cyChar ;
     TCHAR       szBuffer[10] ;
     HDC         hdc ;
     int         i ;
     PAINTSTRUCT ps ;
     TEXTMETRIC  tm ;
 
     switch (message)
     {
     case WM_CREATE:
          hdc = GetDC (hwnd) ;
 
          GetTextMetrics (hdc, &tm) ;
          cxChar = tm.tmAveCharWidth ;
          cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
          cyChar = tm.tmHeight + tm.tmExternalLeading ;
 
          ReleaseDC (hwnd, hdc) ;
          return 0 ;
 
     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;
 
          for (i = 0 ; i < NUMLINES ; i++)
          {
               TextOut (hdc, 0, cyChar * i,
                        devcaps[i].szLabel,
                        lstrlen (devcaps[i].szLabel)) ;
 
               TextOut (hdc, 14 * cxCaps, cyChar * i,
                        devcaps[i].szDesc,
                        lstrlen (devcaps[i].szDesc)) ;
 
               SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
               TextOut (hdc, 14 * cxCaps + 35 * cxChar, cyChar * i, szBuffer,
                        wsprintf (szBuffer, TEXT ("%5d"),
                             GetDeviceCaps (hdc, devcaps[i].iIndex))) ;
 
               SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
          }
 
          EndPaint (hwnd, &ps) ;
          return 0 ;
 
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

前两个设备参数,HORZSIZE和VERTSIZE,文件中称为「以毫米计的实际屏幕的宽度」及「以毫米计的实际屏幕的高度」)。

关于色彩

在大多数GDI函数呼叫中,使用COLORREF值(只是一个32位的无正负号长整数)来表示一种色彩。COLORREF值按照红、绿和蓝色的亮度指定了一种颜色,通常叫做「RGB色彩」。32位的COLORREF值的设定如下图所示:

注意最前面是标为0的8个位,并且每种原色都指定为一个8位的值。理论上,COLORREF可以指定二的二十四次方种或一千六百万种色彩。

这个无正负号长整数常常称为一个「RGB色彩」。Windows表头文件WINGDI.H提供了几种使用RGB色彩值的宏。RGB宏要求三个参数分别代表红、绿和蓝值,然后将它们组合为一个无正负号长整数:

#define RGB(r,g,b) ((COLORREF)(((BYTE)(r) | /        
                   ((WORD)((BYTE)(g)) << 8)) | /        
                   (((DWORD)(BYTE)(b)) << 16)))

注意三个参数的顺序是红、绿和蓝。因此,RGB (255, 255, 0)是0x0000FFFF,或黄色(红色和绿色的合成)。

设备内容属性

Windows使用设备内容来保存控制GDI函数在显示器上如何操作的「属性」。例如,在用TextOut函数显示文字时,程序写作者不必指定文字的色彩和字体,Windows从设备内容取得这个信息。

程序取得一个设备内容的句柄时,Windows用默认值设定所有的属性。下面列出了部分设备内容属性,程序可以改变或者取得任何一种属性。
Windows程序设计:GDI结构和设备内容_第1张图片

保存设备内容

通常,在您呼叫GetDC或BeginPaint时,Windows用默认值建立一个新的设备内容,您对属性所做的一切改变在设备内容用ReleaseDC或EndPaint呼叫释放时,都会丢失。如果您的程序需要使用非内定的设备内容属性,则您必须在每次取得设备内容句柄时初始化设备内容:

case WM_PAINT: 
       hdc = BeginPaint (hwnd, &ps) ; 
       //初始化设备内容属性,绘制窗口显示区域
       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); 
       //初始化设备内容属性
       ReleaseDC(hwnd, hdc);

CS_OWNDC风格只影响GetDC和BeginPaint获得的设备内容,不影响其它函数(如GetWindowDC)获得的设备内容。以前不提倡使用CS_OWNDC风格,因为它需要内存;现在,在处理大量图形的Windows NT应用程序中,它可以提高性能。即使用了CS_OWNDC,您仍然应该在退出窗口消息处理程序之前释放设备内容。

某些情况下,您可能想改变某些设备内容属性,用改变后的属性进行绘图,然后恢复原来的设备内容。要简化这一过程,可以通过如下呼叫来保存与恢复设备内容的状态:

idSaved = SaveDC(hdc);       //保存设备内容的状态
RestoreDC(hdc, idSaved);     //回到呼叫SaveDC前存在的设备内容时

您可以在呼叫RestoreDC之前呼叫SaveDC数次。

当您呼叫SaveDC时,不需要保存传回值,这样只能将设备内容恢复到最近由SaveDC函数保存的状态中:

SaveDC(hdc);
RestoreDC(hdc, -1);

你可能感兴趣的:(Windows程序设计:GDI结构和设备内容)