现在的位置: 首页 > 综合 > 正文

30、Windows API GDI(2)

2011年08月23日 ⁄ 综合 ⁄ 共 9316字 ⁄ 字号 评论关闭

一、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);
}

2DC的操作

GetDC

CreateDC 除了GetDC函数外CreateDC也可以获取DC的句柄。

ReleaseDC ReleaseDC的作用是释放DC,使其他应用程序可以使用。

DeleteDC DeleteDC的功能是释放DC的相关系统资源。

3、颜色的表示

COLORREF类型和RGB

GDI中使用红、绿、蓝三原色的组合来表示颜色。使用38位的数据组合来表示颜色,称作RGB字节,可以表示0x1000000种颜色。RGBQUAD数据结构用于表示RGB颜色,也可以使用COLORREF数据类型来表示,COLORREFDWORD大小相同,RGB宏可以将颜色表示为COLORREFGetRValueGetGValueGetBValue3个宏可以将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;
}

【上篇】
【下篇】

抱歉!评论已关闭.