一、GDI的几个示例与概念
1、笔和话刷的基本操作
示例
/* 头文件 */
#include < Windows.h >
/* 函数声明 */
void GdiOut(HDC hdc);
// WinMain
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
HDC hdc = GetDC(NULL);
GdiOut(hdc);
ReleaseDC(NULL, hdc);
}
/* ************************************
* VOID GdiOut(HDC hdc)
* 功能 演示GDI基本功能的使用
* 参数 HDC hdc,用于显示所绘制的图像
* 无返回值
************************************* */
VOID GdiOut(HDC hdc)
{
HPEN hpen, hpenOld;
HBRUSH hbrush, hbrushOld;
// 初始的颜色
BYTE bRed = 0 ;
BYTE bGreen = 0 ;
BYTE bBlue = 0 ;
// 笔的颜色 正黑
COLORREF cPen = RGB(bRed, bGreen, bBlue);
// 从COLORREF类型拆解颜色,设置笔刷的颜色,这里为紫偏蓝
COLORREF cBrush = RGB( 233 , GetGValue(cPen), 255 );
// 创建笔
hpen = CreatePen(PS_SOLID, 10 , cPen);
// 创建笔刷
hbrush = CreateSolidBrush(cBrush);
// 为DC选择笔和笔刷
hpenOld = (HPEN)SelectObject(hdc, hpen);
hbrushOld = (HBRUSH)SelectObject(hdc, hbrush);
// 绘制线条
LineTo(hdc, 500 , 500 );
// 使用初始的笔
SelectObject(hdc,hpenOld);
// 绘制矩形
Rectangle( hdc, 200 , 200 , 500 , 500 );
// 释放资源
DeleteObject(hpen);
SelectObject(hdc, hbrushOld);
DeleteObject(hbrush);
}
◇ GetDC
◇ CreateDC 除了GetDC函数外CreateDC也可以获取DC的句柄。
◇ ReleaseDC ReleaseDC的作用是释放DC,使其他应用程序可以使用。
◇ DeleteDC DeleteDC的功能是释放DC的相关系统资源。
3、颜色的表示
COLORREF类型和RGB宏
在GDI中使用红、绿、蓝三原色的组合来表示颜色。使用3个8位的数据组合来表示颜色,称作RGB字节,可以表示0x1000000种颜色。RGBQUAD数据结构用于表示RGB颜色,也可以使用COLORREF数据类型来表示,COLORREF与DWORD大小相同,RGB宏可以将颜色表示为COLORREF。GetRValue、GetGValue,GetBValue这3个宏可以将COLORREF拆解为三原色的字节。
DC中可用的颜色信息
使用NUMCOLORS参数,调用GetDeviceCaps API函数即可获得指定DC的颜色数量。再使用EnumObjects函数就可以列举指定DC的所有颜色的表示。
4、字体操作
示例
/* 头文件 */
#include < Windows.h >
/* ************************************
* HFONT ChooseNewFont()
* 功能 选择字体
*
* 返回值 返回字体句柄
************************************* */
HFONT ChooseNewFont()
{
CHOOSEFONT cf;
LOGFONT lf;
HFONT hfont;
// CHOOSEFONT 结构
cf.lStructSize = sizeof (CHOOSEFONT);
cf.hwndOwner = (HWND)NULL;
cf.hDC = (HDC)NULL;
cf.lpLogFont = & lf;
cf.iPointSize = 0 ;
cf.Flags = CF_SCREENFONTS;
cf.rgbColors = RGB( 0 , 0 , 0 );
cf.lCustData = 0L ;
cf.lpfnHook = (LPCFHOOKPROC)NULL;
cf.lpTemplateName = (LPSTR)NULL;
cf.hInstance = (HINSTANCE) NULL;
cf.lpszStyle = (LPSTR)NULL;
cf.nFontType = SCREEN_FONTTYPE;
cf.nSizeMin = 0 ;
cf.nSizeMax = 0 ;
// 选择字体对话框
ChooseFont( & cf);
// 得到HFONT 返回
hfont = CreateFontIndirect(cf.lpLogFont);
return (hfont);
}
/* ************************************
* WinMain
* 功能 选择字体,并将文字显示在界面上
*
************************************* */
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
HDC hdc = GetDC(NULL);
int XIncrement = 10 ;
int YStart = 50 ;
TEXTMETRIC tm;
HFONT hfntDefault, hfntChoose;
SIZE sz;
UINT uAlignPrev;
LPSTR lpszString1 = " 字符串一 " ;
LPSTR lpszString2 = " 字符串二 " ;
LPSTR lpszString3 = " 字符串三 " ;
DWORD dwStrLen1 = lstrlen(lpszString1);
DWORD dwStrLen2 = lstrlen(lpszString2);
DWORD dwStrLen3 = lstrlen(lpszString3);
// 选择字体
hfntChoose = ChooseNewFont();
// 设置颜色
SetBkColor(hdc,RGB( 255 , 255 , 255 ));
SetTextColor(hdc,RGB( 255 , 0 , 0 ));
SetBkMode(hdc,TRANSPARENT);
// 输出字符串一
TextOut(hdc, XIncrement, YStart, lpszString1, dwStrLen1);
// 为字符串二设置输出位置
GetTextExtentPoint32(hdc, lpszString1, dwStrLen1, & sz);
XIncrement += sz.cx;
GetTextMetrics(hdc, & tm);
XIncrement -= tm.tmOverhang;
// 改变字体
hfntDefault = (HFONT)SelectObject(hdc, hfntChoose);
// 输出字符串二
TextOut(hdc, XIncrement, YStart, lpszString2, dwStrLen2);
// 设置字符串三的输出位置
GetTextExtentPoint32(hdc, lpszString1, dwStrLen1, & sz);
XIncrement = 10 ;
YStart += sz.cy;
GetTextMetrics(hdc, & tm);
XIncrement -= tm.tmOverhang;
// 设置为默认字体
SelectObject(hdc, hfntDefault);
// 输出字符串三
uAlignPrev = SetTextAlign(hdc, TA_UPDATECP);
MoveToEx(hdc, XIncrement, YStart, (LPPOINT)NULL);
TextOut(hdc, 0 , 0 , lpszString3, dwStrLen3);
SetTextAlign(hdc, uAlignPrev);
// Clear
DeleteObject(hfntChoose);
SetBkMode(hdc, OPAQUE);
DeleteDC( hdc );
return 0 ;
}
遍历字体
/* 头文件 */
#include < Windows.h >
#include < stdio.h >
/* 函数声明 */
BOOL CALLBACK EnumFamCallBack(LPLOGFONT , LPNEWTEXTMETRIC , DWORD , LPVOID ) ;
DWORD ListFont(HWND hwnd);
// main
int main()
{
// 桌面DC
ListFont(NULL);
}
/* ************************************
* DWORD ListFont(HWND hwnd)
* 功能 列举指定窗口的DC的所具有的字体
************************************* */
DWORD ListFont(HWND hwnd)
{
// 获得DC
HDC hdc = GetDC(hwnd);
// 用于计数
int aFontCount[] = { 0 , 0 , 0 };
// 调用EnumFontFamilies,开始列举,
EnumFontFamilies(hdc, (
LPCTSTR) NULL, // 列举所有类型
(FONTENUMPROC) EnumFamCallBack, // 回调函数为EnumFamCallBack
(LPARAM) aFontCount); // 传递给EnumFamCallBack的参数
// 显示统计信息
printf( " Number of raster fonts: %d\n " ,aFontCount[ 0 ]);
printf( " Number of vector fonts: %d\n " ,aFontCount[ 1 ]);
printf( " Number of TrueType fonts: %d\n " ,aFontCount[ 2 ]);
// 返回
return 0 ;
}
/* ************************************
* EnumFamCallBack
* 功能 字体列举回调函数次
* 每列举一个字体会被调用一次
* 参数 lplf,字体的LOGFONT结构
* lpntm,字符的尺度属性
* FontType,字体类型
* lParam,通过EnumFontFamilies输入给本函数的参数,这里用于计数
************************************* */
BOOL CALLBACK EnumFamCallBack(
LPLOGFONT lplf,
LPNEWTEXTMETRIC lpntm,
DWORD FontType,
LPVOID aFontCount)
{
// 获得参数
PINT aiFontCount = (PINT) aFontCount;
// 判断字体类型,输出类型信息,并根据类型进行计数
if (FontType & RASTER_FONTTYPE)
{
printf( " RASTER TYPE \t " );
aiFontCount[ 0 ] ++ ;
}
else if (FontType & TRUETYPE_FONTTYPE)
{
printf( " TRUETYPE \t " );
aiFontCount[ 2 ] ++ ;
}
else
{
printf( " VECTOR TYPE \t " );
aiFontCount[ 1 ] ++ ;
}
// 显示字体信息
printf( " %s\tItalic = %d\n " ,lplf -> lfFaceName,lplf -> lfItalic);
// 返回
if (aiFontCount[ 0 ] || aiFontCount[ 1 ] || aiFontCount[ 2 ])
return TRUE;
else
return FALSE;
}
EnumFontFamilies函数是实现列举DC中已经安装的字体的API函数;EnumFontFamilies函数指定了一个回调函数,每列举一个字体,回调函数就会被调用一次,字体的LOGFONT结构、字体的类型会作为参数输出给回调函数。
5、绘制线条
在绘制线条前需将线条所使用的画笔对象选择入DC。画笔对象决定了所绘制线条的颜色、宽度、样式。
示例鼠标跟踪
/* 头文件 */
#include < windows.h >
/* 预定义 */
#define MAXGUIDESEGMENTS 1000
#define MyAlloc(dwSize) HeapAlloc(GetProcessHeap(),0,dwSize)
#define MyFree(lpMem) HeapFree(GetProcessHeap(),0,lpMem);
/* 函数声明 */
BOOL GetGuideLine(HWND, LPPOINT * , LPDWORD);
BOOL ShowGuide(HDC, LPPOINT, DWORD);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
DWORD GetLastErrorBox(HWND hWnd, LPSTR lpTitle);
/* 全局变量 */
HINSTANCE hInst;
LPSTR szAppName = " Curves " ;
LPSTR szTitle = " Curves Application " ;
/* ************************************
* WinMain
* 功能 创建窗口
************************************* */
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASS wc;
hInst = hInstance;
// 注册窗口类
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;
if ( ! RegisterClass( & wc))
{
GetLastErrorBox(NULL, " Error in RegisterClass " );
return (FALSE);
}
// 创建窗口
hWnd = CreateWindow(
szAppName,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0 , CW_USEDEFAULT, 0 ,
NULL,
NULL,
hInstance,
NULL
);
if ( ! hWnd)
{
GetLastErrorBox(hWnd, " Error in CreateWindow " );
return (FALSE);
}
// 显示更新
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 消息循环
while (GetMessage( & msg, NULL, 0 , 0 ))
{
TranslateMessage( & msg);
DispatchMessage( & msg);
}
return ( int )(msg.wParam);
UNREFERENCED_PARAMETER(lpCmdLine);
}
/* ************************************
* WndProc
* 功能 窗口消息处理函数
************************************* */
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT message,
WPARAM uParam,
LPARAM lParam)
{
static BOOL bOn = TRUE;
static LPPOINT lpBlue = NULL;
static LPPOINT lpRed = NULL;
static DWORD dwBlue = 0 ;
static DWORD dwRed = 0 ;
static BOOL bOutlineOnly = FALSE;
static BOOL bShowGuides = TRUE;
static HPEN hpenBlue, hpenRed;
switch (message)
{
case WM_CREATE:
{
// 获取DC
HDC hDC = GetDC(hWnd);
// 创建笔对象
hpenBlue = CreatePen(PS_SOLID, 1 , RGB( 0 , 0 , 255 ));
hpenRed = CreatePen(PS_SOLID, 1 , RGB( 255 , 0 , 0 ));
}
GetLastErrorBox(hWnd, " Error in WM_CREATE " );
break ;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, & ps);
RECT rect;
// 将客户区绘制为白色
GetClientRect(hWnd, & rect);
PatBlt(hDC, 0 , 0 , rect.right, rect.bottom, WHITENESS);
// 即存在红线,又存在蓝线
if (dwBlue && dwRed)
{
// 显示蓝线
if (dwBlue && bShowGuides)
{
SelectObject(hDC, hpenBlue);
ShowGuide(hDC, lpBlue, dwBlue);
SelectObject(hDC, GetStockObject(BLACK_PEN));
}
// 显示红线
if (dwRed && bShowGuides)
{
SelectObject(hDC, hpenRed);
ShowGuide(hDC, lpRed, dwRed);
SelectObject(hDC, GetStockObject(BLACK_PEN));
}
}
EndPaint(hWnd, & ps);
}
break ;
case WM_LBUTTONDOWN:
{
HDC hDC = GetDC(hWnd);
RECT rect;
if (bOn) // 消除并画蓝线
{
// 将客户区填充为白色
GetClientRect(hWnd, & rect);
PatBlt(hDC, 0 , 0 , rect.right, rect.bottom, WHITENESS);
// 释放资源
if (lpBlue)
MyFree(lpBlue);
if (lpRed)
MyFree(lpRed);
dwRed = 0 ;
dwBlue = 0 ;
// 开始跟踪鼠标移动,绘制蓝线
SelectObject(hDC, hpenBlue);
GetGuideLine(hWnd, & lpBlue, & dwBlue);
}
else // 画红线
{
// 开始跟踪鼠标移动,绘制红线
SelectObject(hDC, hpenRed);
GetGuideLine(hWnd, & lpRed, & dwRed);
}
// 鼠标左键放开,恢复笔对象
SelectObject(hDC, GetStockObject(BLACK_PEN));
// 取反,在红色和蓝色间交替
bOn = ! bOn;
}
GetLastErrorBox(hWnd, " Error in WM_LBUTTONDOWN " );
break ;
case WM_DESTROY:
// 释放资源,退出
if (lpBlue) MyFree(lpBlue);
if (lpRed) MyFree(lpRed);
PostQuitMessage( 0 );
break ;
default :
return (DefWindowProc(hWnd, message, uParam, lParam));
}
return ( 0 );
}
/* ************************************
* BOOL GetGuideLine(HWND hWnd, LPPOINT *lpPoint, LPDWORD lpdwNumPts)
* 功能 跟踪鼠标,绘制鼠标轨迹
* 参数 hWnd,窗口
* lpPoint,用于保存点的数组,向调用函数返回
* lpdwNumPts,返回的数组的大小
************************************* */
BOOL GetGuideLine(HWND hWnd, LPPOINT * lpPoint, LPDWORD lpdwNumPts)
{
MSG msg;
HDC hDC = GetDC(hWnd);
BOOL bFirstTime = TRUE;
DWORD dwPos = 0 ;
RECT rect;
SetCapture(hWnd); // 设置鼠标捕获器
GetClientRect(hWnd, & rect);
// 为点数组分配空间
* lpPoint = (LPPOINT)MyAlloc(MAXGUIDESEGMENTS * sizeof (POINT));
for (;;)
{
// 过滤所有鼠标消息
WaitMessage();
if (PeekMessage( & msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
{
// 判断是否在客户区中
if ((LOWORD(msg.lParam) < rect.right) && (HIWORD(msg.lParam) <
rect.bottom))
{
// 是否第一次收到消息
if (bFirstTime)
{
bFirstTime = FALSE;
// 如果是第一次将笔的起点移动到鼠标点击的位置
MoveToEx(hDC, LOWORD(msg.lParam), HIWORD(msg.lParam),
NULL);
}
// 是否达到了最大点数
if (dwPos < MAXGUIDESEGMENTS)
{
// 鼠标的移动会产生鼠标消息,每收到一次消息保存一个点
。
( * lpPoint)[dwPos].x = LOWORD(msg.lParam);
( * lpPoint)[dwPos].y = HIWORD(msg.lParam);
// 绘制到鼠标所在的点
LineTo(hDC, ( * lpPoint)[dwPos].x, ( * lpPoint)
[dwPos].y);
dwPos ++ ;
}
}
if (msg.message == WM_LBUTTONUP)
break ;
}
else
continue ;
}
* lpdwNumPts = dwPos;
ReleaseDC(hWnd, hDC);
ReleaseCapture();
DeleteDC( hDC );
return TRUE;
}
/* ************************************
* BOOL ShowGuide(HDC hDC, LPPOINT lpPoints, DWORD dwNumPts)
* 功能 根据保存的点的数组重绘曲线
* 参数 hWnd,窗口
* lpPoint,保存的点的数组,
* dwNumPts,数组的大小
************************************* */
BOOL ShowGuide(HDC hDC, LPPOINT lpPoints, DWORD dwNumPts)
{
Polyline(hDC, lpPoints, dwNumPts);
return TRUE;
}
// 显示错误信息
DWORD GetLastErrorBox(HWND hWnd, LPSTR lpTitle)
{
LPVOID lpv;
DWORD dwRv;
if (GetLastError() == 0 ) return 0 ;
dwRv = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPSTR) & lpv,
0 ,
NULL);
MessageBox(hWnd, (LPCSTR)lpv, lpTitle, MB_OK);
if (dwRv)
LocalFree(lpv);
SetLastError( 0 );
return dwRv;
}
二、相关API
1、定义图形对象:
CreatePen
CreateSolidBrush,CreateHatchBrush,CreatePatternBrush系列
2、图形对象的选择
SeleteObject
DC中每一类图形对象有一个“当前”图形对象(一个DC中同一时刻只能有一个画笔对象,也只能有一个画刷对象)。
3、绘制图形和线条
LineTo
MoveToEx
4、选择、设置字体
CreateFont,CreateFontIndirect
ChooseFont
填充LOGFONT结构
用于创建字体的LOGFONT结构成员较多,各成员的意义也不十分明确,在使用LOGFONT表示一个字体时,填充比较复杂。但是在程序设计时,一般可由程序来完成填充。有两种方法可供选用:一是使用ChooseFont API函数弹出选择字体选择对话由用户选择,ChooseFont函数会返回用户选择的字体所对应的LOGFONT结构。二是遍历系统中已经安装的字体,遍历程序会返回每一个字体所对应的LOGFONT结构,在得到LOGFONT结构后,直接调用CreateFontIndirect API函数就可以得到字体的句柄HFONT。
5、设置颜色
SetTextColor
6、输出文字
DrawText
TextOut
GetTextExtentPoint32函数的功能是计算使用当前文本输出指定字符串后,输出的字符串的长和高(像素)。在使用TextOut等函数进行文字显示时,可以用于定义下次显示的文字的位置。
GetTextMetrics函数用于获取文本的尺度信息。SetTextAlign函数可以指定DC的文本输出对齐方式。
7、设置背景色
SetBkMode
8、安装删除字体
AddFontResource
RemoveFontResource
9、绘制线条[3]
直线:
LineTo
MoveToEx
绘制任意曲线
PolyBezier、Polyline、PolylineTo、PolyPolyline
SetCapture
ArcTo用于绘制椭圆弧线
参考
[1] 精通Windows API 函数、接口、编程实例
[2] http://msdn.microsoft.com/en-us/library/dd183553%28VS.85%29.aspx
[3] http://msdn.microsoft.com/en-us/library/dd162811%28VS.85%29.aspx