GDI:Graphics Device Interface,图形设备接口
- 设备环境 (Device Context)
- 设备环境是Windows 内部使用的数据结构,,它定义了GDI 函数在显示设备特定区域的工作方式。
- BeginPaint函数取得窗口客户区无效区域的设备环境句柄
- GetWindowDC函数能够取得整个窗口的设备环境句柄
- 如果不是在处理 WM_PAINT 消息,可以使用GetDC 函数取得窗口客户区的设备环境句柄,进而进行绘制操作
- 设备环境是Windows 内部使用的数据结构,,它定义了GDI 函数在显示设备特定区域的工作方式。
- Windows 的颜色和像素点
- 在Win32 编程中,统一使用32 位的整数(一个COLORREF 值)来表示深度为24 位的颜色。
- 设置一个象素点的值可以用SetPixel 函数
- COLORREF SetPixel(
- HDC hdc, // 设备环境句柄
- int X, // 象素的X 坐标
- int Y, // 象素的Y 坐标
- COLORREF crColor // 要设置的COLORREF 值
- );
- 如果需要获取DC 中某个像素点当前的颜色值,可以使用GetPixel 函数。
- COLORREF GetPixel( HDC hdc, int nXPos, int nYPos);
- 绘制线条
- 绘制线条的函数有画单条直线的 LineTo,画多条直线的 Polyline 和PolylineTo,画贝塞儿曲线的PolyBezier 和PolyBezierTo,画弧线的 Arc 和 ArcTo。
- 当前点的位置,可以使用MoveToEx 函数
- BOOL MoveToEx(
- HDC hdc, // 设备环境句柄
- int X, // 新位置的X 坐标
- int Y, // 新位置的Y 坐标
- LPPOINT lpPoint // 用来返回原来的当前点位置,如果不需要的话,这个参数可以被设为NULL
- )
- 例如:
- ::MoveToEx(hDC, 0, 0, NULL);
- ::LineTo(hDC, 0, 500);
- 绘制的是相连的多条直线,Polyline连接点;PolylineTo从当前点开始连接点
- BOOL Polyline(HDC hdc, CONST POINT *lpPoint, int cPoints);
- BOOL PolylineTo(HDC hdc, CONST POINT *lpPoint, DWORD cPoints );
- 画笔
- 预定义画笔:BLACK_PEN、WHITE_PEN、NULL_PEN
- // 获取预定义画笔的句柄。Stock 的中文含义是常备的、库存的
- HPEN hPen = (HPEN)::GetStockObject(BLACK_PEN);
- // 将画笔对象选入设备。SelectObject函数会根据句柄的种类自动替换掉原来的对象,并返回原对象句柄
- HPEN hOldPen = (HPEN)::SelectObject(hdc, hPen);
- 以创建自定义的画笔对象
- HPEN CreatePen(
- int fnPenStyle, // 画笔的风格,取值有PS_SOLID、PS_DASH、PS_DOT、PS_DASHDOT 等
- int nWidth, // 画笔的宽度,单位是DC 坐标映射方法中定义的逻辑单位
- COLORREF crColor // 画笔的颜色
- );
- 预定义画笔:BLACK_PEN、WHITE_PEN、NULL_PEN
- 绘制区域
- 绘制边线的时候要使用画笔,填充区域就要使用画刷了。绘制区域的函数工作的时候以当前画笔绘制边线,并以当前画刷填充中间的区域。这些函数有画矩形的Rectangle,画椭圆的Ellipse,画多边形的Polygon,画弦的Chord 等,
- Rectangle(hdc, x1, y1, x2, y2); // 画以(x1, y1)和(x2, y2)为对角坐标的填充矩形
- Ellipse(hdc, x1, y1, x2, y2); // 以(x1, y1)和(x2, y2)为对角坐标定义一个矩形,然后画矩形相切的椭圆并填充
- Polygon(hdc, lpPoint, 5) // lpPoint 指向存放(x0, y0)到(x4, y4)的内存,函数从(x1, y1)到(x2, y2)...到(x4, y4),再回到(x1, y1),一共画5 条直线并填充
- CreateSolidBrush函数创建了新的单色的画刷对象
- HBRUSH CreateHatchBrush(
- int fnStyle, // 线条的风格
- COLORREF clrref // 图案线条的颜色
- );
- fnStyle 参数指定了不同风格的线条,这些图案线条实际上是由8×8 的位图重复铺开组成的。此参数取值可以是HS_BDIAGONAL、HS_FDIAGONAL、HS_CROSS、HS_HORIZONTAL、HS_DIAGCROSS 或HS_VERTICAL
- 当然,Windows 也预定义了一些画刷对象,可以被GetStockObject 函数获取,并被选入DC 中。这些常用的预定义对象有BLACK_BRUSH(黑色画刷)、DKGRAY_BRUSH(深灰色画刷)、GRAY_BRUSH(灰色画刷)、LTGRAY_BRUSH(浅灰色画刷)、WHITE_BRUSH(白色画刷)、NULL_BRUSH(空画刷)等。
- 绘制边线的时候要使用画笔,填充区域就要使用画刷了。绘制区域的函数工作的时候以当前画笔绘制边线,并以当前画刷填充中间的区域。这些函数有画矩形的Rectangle,画椭圆的Ellipse,画多边形的Polygon,画弦的Chord 等,
- 坐标系统
- 坐标映射方式是设备环境中一个很重要的属性。它的默认值是 MM_TEXT,即以左上角为坐标原点,以右方当做x 坐标的正方向,以下方当做y 坐标的正方向。可以用SetMapMode 函数改变DC 中的坐标映射方式。
- int SetMapMode(
- HDC hdc, // 设备环境句柄
- int fnMapMode // 新的坐标映射方式
- );
- fnMapMode 映射方法可取:MM_TEXT (像素),MM_LOMETRIC (0.1mm),MM_HIMETRIC (0.01mm),MM_LOENGLISH 0.01 英寸,MM_HIENGLISH 0.001 英寸,MM_TWIPS 1/1440 英寸,M_ISOTROPIC 用户自定义(X=Y),MM_ANISOTROPIC 用户自定义(X!=Y)
- 调用 SetWindowExtEx 函数设置坐标系的逻辑单位
- BOOL SetWindowExtEx(
- HDC hdc, // 设备环境句柄
- int nXExtent, // 新的宽度(映射方式为MM_ISOTROPIC 时nXExtent 必须等于nYExtent)
- int nYExtent, // 新的高度
- LPSIZE lpSize // 用于返回原来的大小,不需要的话可以设它为NULL
- );
- 调用 SetViewportExtEx 函数设置x、y 坐标轴的方向和坐标系包含的范围,即定义域和值域。
- BOOL SetViewportExtEx(
- HDC hdc, // 设备环境句柄
- int nXExtent, // 新的宽度(以像素为单位,定义域)
- int nYExtent, // 新的高度(以像素为单位,值域)
- LPSIZE lpSize // 用于返回原来的大小,不需要的话可以设它为NULL
- );
- 设置坐标系的原点坐标SetViewportOrgEx(
- BOOL SetViewportOrgEx(
- HDC hdc, // 设备环境句柄
- int X, // 原点的横坐标
- int Y, // 原点的纵坐标
- LPPOINT lpPoint // 用于返回原来的坐标,不需要的话可以设它为 NULL
- );
- 例如:以整个客户区为边界画一个椭圆
void OnPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc = ::BeginPaint(hWnd, &ps); // 取得客户区的大小 RECT rt; ::GetClientRect(hWnd, &rt); int cx = rt.right; int cy = rt.bottom; // 设置客户区的逻辑大小为500 乘500,原点为(0,0) ::SetMapMode(hdc, MM_ANISOTROPIC); // 设置坐标映射关系 ::SetWindowExtEx(hdc, 500, 500, NULL); // 不管真实窗口的大小是多少,程序已经告诉了Windows 该窗口的逻辑大小是500×500 ::SetViewportExtEx(hdc, cx, cy, NULL); // 设置x, y轴的区域 ::SetViewportOrgEx(hdc, 0, 0, NULL); // 设置坐标原点 ::Ellipse(hdc, 0, 0, 500, 500); // 以整个客服区为边界画一个椭圆 ::EndPaint(hWnd, &ps); }
- 坐标映射方式是设备环境中一个很重要的属性。它的默认值是 MM_TEXT,即以左上角为坐标原点,以右方当做x 坐标的正方向,以下方当做y 坐标的正方向。可以用SetMapMode 函数改变DC 中的坐标映射方式。
- Windows 内存DC
- 利用Windows 内存DC进行绘图,可以减少屏幕闪烁。把所要绘制的一切先在内存DC中进行绘制,之后全部搬到屏幕DC中。
- 利用内存DC绘图的方法为:
- 创建关于屏幕DC的内存DC
- MemDC.CreateCompatibleDC(pDC);
- 创建一个关于屏幕DC的图画
- CRect rect;
- this->GetClientRect(rect); // 得到客户区的大小
- CBitmap bmpFace;
- bmpFace.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
- 将这幅画选入内存DC中
- CBitmap* pOldBmp = NULL:
- pOldBmp = MemDC.SelectObject(&bmpFace);
- 在内存DC中进行任何绘制动作
- CBrush brush(RGB(255, 255, 255));
- MemDC.FillRect(rect, &brush);
- for (int i = 0; i < 500; i++)
- {
- MemDC.MoveTo(22+i, 22);
- MemDC.LineTo(22+i, 222);
- }
- 绘制完后将内存DC中的这幅画会知道屏幕DC中
- pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDC, rect.left, rect.top, SRCCOPY);
- 进行相关资源的回收动作
- MemDC.SelectObject(pOldBmp);
- bmpFace.DeleteObject();
- 同事需要把系统的ON_WM_ERASEBKGND消息进行修改,否则也会出现闪烁情况
- 创建关于屏幕DC的内存DC