30、Windows API GDI(2)
一、GDI的几个示例与概念
1、笔和话刷的基本操作
示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
**************************************/
/* 头文件 */
#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、字体操作
示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
**************************************/
/* 头文件 */
#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;
}
遍历字体
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
**************************************/
/* 头文件 */
#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。画笔对象决定了所绘制线条的颜色、宽度、样式。
示例鼠标跟踪
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
**************************************/
/* 头文件 */
#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