一、GDI的几个示例与概念

1、笔和话刷的基本操作

示例



30、Windows API GDI(2)_ide30、Windows API GDI(2)_字符串_02画笔示例


**************************************/

/* 头文件 */

#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);

}

2、DC的操作

◇ 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、字体操作

示例


30、Windows API GDI(2)_ide30、Windows API GDI(2)_字符串_02字体示例


**************************************/

/* 头文件 */

#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;

}


遍历字体


30、Windows API GDI(2)_ide30、Windows API GDI(2)_字符串_02遍历字体


**************************************/

/* 头文件 */

#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。画笔对象决定了所绘制线条的颜色、宽度、样式。

示例鼠标跟踪


30、Windows API GDI(2)_ide30、Windows API GDI(2)_字符串_02绘制线条


**************************************/

/* 头文件 */

#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用于绘制椭圆弧线