如果我们希望在图形输出设备上绘制图形,必须首先获取设备环境(即 DC)的句柄。
当 Windows 把这个句柄交给你的程序,Windows 同时也就给予你使用这个设备的权限。
接着,GDI 函数将这个句柄作为一个参数,告诉 Windows 在哪个设备上进行绘图。
获取设备环境句柄:
获取和释放设备环境句柄的最常用的方法是在处理 WM_PAINT 消息时调用 BeginPaint(hwnd,&ps) 和 EndPaint(hwnd,&ps)。
设备环境还可以在处理非 WM_PAINT 消息时由 Windows 程序获取。调用 GetDC(hwnd) 和 ReleaseDC(hwnd,hdc)。
// GetDC(),GetWindowDC(),CreateDC()返回值都为 hdc。
Windows 程序还可以获得用于整个窗口,而不仅仅是窗口客户去的句柄。调用 GetWindowDC(hwnd) 和 ReleaseDC(hwnd,hdc)。
更通用的用于获取设备环境的句柄的函数。调用 CreateDC(lpszDriver,lpszDevice,lpszOutput,lpinitData) 和 DeleteDC(hdc)。
// 获取整个屏幕的设备环境句柄 hdc = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
处理位图时,可调用 CreateCompatibleDC() 和 DeleteDC()。 // 这两个简单看看就行。
处理图元文件时,可调用 CreateMetaFile() 和 CloseMetaFile()。
获取设备环境信息:
函数原型:int GetDeviceCaps(HDC hdc, int nlndex);
函数返回值:int, 设备相关信息的尺寸大小。
1、hdc:设备上下文环境的句柄。
2、nIndex:指定返回项。常用到的值:
HORZSIZE:物理屏幕的宽度(毫米);VERTSIZE:物理屏幕的高度(毫米);
HORZRES:屏幕的宽度(像素);VERTRES:屏幕的高度(光栅线);
BITSPIXEL:像素相连颜色位数;PLANES:颜色位面数;NUMBRUSHES:设备指定画刷数;
NUMCOLORS:设备颜色表的入口数,如果设备的色深不超过8位像素。对于超过色深的设备返回-1;
设备环境属性:
Windows 在设备环境中存储着一些“属性”,这些属性控制 GDI 函数在显示器上的操作方式。
当一个程序获取一个设备环境句柄时,Windows 设置所有的属性为默认值。
有许多 API 函数可以获取其值或者修改其值。
保存设备环境:
通常,当调用 GetDC() 或者 BeginPaint() 时, Windows 返回一个设备环境,它的所有属性都被设定为默认值。
而当设备环境调用 ReleaseDC() 或者 EndPaint() 时,对属性做的任何改变都会消失。
我们可以在注册窗口类时将 CS_OWNDC 标志作为窗口类样式的一部分来保存设备环境。
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC ;
现在每个基于这个窗口类创建的窗口都有它私有的设备环境,当窗口被销毁时,这个设备环境任然存在。
使用 CS_OWNDC 样式时,只需要初始化设备环境属性一次。
但是 CS_OWNDC 样式仅影响通过 GetDC() 和 BeginPaint() 获得的设备环境,通过其他的函数获得的设备环境不受影响。
某些情况下,可能想改变某些设备环境属性,然后使用变更后的属性进行绘制,接着再恢复原来的设备环境。
可以调用如下函数来保存设备环境的状态:
idSaved = SaveDC(hdc) ;
现在可以改变一些属性,而调用下面的函数则可以返回调用 SaveDC() 之前存在的设备环境:
RestoreDC(hdc, idSaved);
还有一种像汇编语言中的 PUSH 和 POP 指令般的调用方式:
SaveDC(hdc);
RestoreDC(hdc,,-1);
这会使设备环境恢复到最近一次由 SaveDC() 保存的状态。
点和线的绘制:
注意:点的坐标都是相对客户区左上角而言的。
SetPixel() 介绍:
功能:该函数将指定坐标处的像素设为指定的颜色。
函数原型:COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF crColor);
参数:hdc 设备环境句柄。
X 指定要设置的点的X轴坐标,按逻辑单位表示坐标。
Y 指定要设置的点的Y轴坐标,按逻辑单位表示坐标。
crColor 指定要用来绘制该点的颜色。
返回值: 如果函数执行成功,那么返回值就是函数设置像素的RGB颜色值。这个值可能与 crColor
指定的颜色有所不同,之所以有时发生这种情况是因为没有找到对指定颜色进行真正匹配造成的。
如果函数失败,那么返回值是-1。
GetPixel() 介绍:
功能:该函数检索指定坐标点的像素的 RGB 颜色值。
函数原型:COLORREF GetPixel(HDC hdc, int nXPos, int nYPos) ;
参数:
hdc:设备环境句柄。
nXPos:指定要检查的像素点的逻辑X轴坐标。
nYPos:指定要检查的像素点的逻辑Y轴坐标。
返回值:返回值是该象像点的 RGB 值。如果指定的像素点在当前剪辑区之外;那么返回值是CLR_INVALID。
备注:该像素点必须在当前剪辑区的边界之内。并不是所有设备都支持GetPixel函数。
应用程序应调用 GetDeviceCaps() 来确定指定的设备是否支持该函数。
MoveToEX() 介绍:
功能:设置设备环境的“当前位置”属性。
函数原型:WINGDIAPI BOOL WINAPI MoveToEx(HDC
hdc, int
X, int
Y, LPPOINT
lpPoint);
参数:
HDC hdc:传入参数,设备上下文句柄。
int X:传入参数:新位置的X坐标。
int Y:传入参数:新位置的Y坐标。
LPPOINT lpPoint:传出参数:一个指向POINT结构的指针,用来存放上一个点的位置。
若此参数为NULL,则不保存上一个点的位置。
返回值:返回TRUE代表移动成功,FALSE代表失败,用 GetLastError() 获得更具体的错误信息。
LineTo() 介绍:
功能:用当前画笔画一条线,从当前位置连到一个指定的点。
该函数与MoveTo函数配合使用。这个函数调用完毕,当前位置变成x,y。
函数原型:WINGDIAPI BOOL WINAPI LineTo(HDC
hdc, int
X, int
Y);
参数:
hdc: 设备场景句柄。
X: 线段终点X坐标位置,采用逻辑坐标表示。这个点不会实际画出来;它不属于线段的一部份。
Y: 线段终点Y坐标位置,采用逻辑坐标表示。这个点不会实际画出来;它不属于线段的一部份。
返回值: 返回TRUE代表移动成功,FALSE代表失败。
GetCurrentPositionEX() 介绍:
功能:获取逻辑坐标中的当前位置。
函数原型:BOOL GetCurrentPositionEx(HDC hdc, LPPOINT lpPoint);
参数:
hdc: 指向设备环境的句柄。
lpPoint:指向接收当前位置坐标的POINT结构的指针。(Point 结构仅含有 x,y 两个变量)。
返回值: 如果函数调用成功,返回值为非零值,否则为零。
Polyline() 介绍:
功能:用当前画笔描绘一系列线段。使用 PolylineTo() 时,当前位置会设为最后一条线段的终点。
它不会由Polyline函数改动。Polyline既不使用也不改变目前位置。
函数原型:BOOL Polyline(HDC hdc, CONST POINT *lppoint, int cPoints) ;
参数:
hdc:绘图的设备环境句柄。
lpPoint:POINT结构数组。
cPoints:POINT结构数组中的点数。会从第一个点到第二个点画一条线,以次类推。
返回值:非零表示成功,零表示失败。
PolylineTo() 介绍:
功能:PolylineTo,和PolyLine不同,PolyLineTo 使用目前位置作为开始点,并将目前位置设定为最后
一根线的终点,根据 apt 的点依次画直线。设置目前位置可调用MoveToEx函数。
函数原型:BOOL PolyLineTo(HDC hdc, CONST POINT * apt, DWORD cpt);
参数:
hdc: 设备场景句柄。
apt: POINT结构数组。
cpt: POINT结构数组中的点数。
例,正弦波曲线:
#include <windows.h>
#include <math.h>
#define NUM 1000
#define TWOPI (2 * 3.14159)
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("SineWave") ;
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 ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Sine Wave Using Polyline"),
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 cxClient, cyClient ;
HDC hdc ;
int i ;
PAINTSTRUCT ps ;
POINT apt [NUM] ;
switch (message)
{
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;
for (i = 0 ; i < NUM ; i++)
{
apt[i].x = i * cxClient / NUM ;
apt[i].y = (int) (cyClient / 2 * (1 - sin (TWOPI * i / NUM))) ;
}
Polyline (hdc, apt, NUM) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}