关键字:HPEN、HBRUSH、HFONT、HBITMAP
在本章中,主要讲述了一些GDI的基本操作。其中有:DC的基本概念、GDI基本绘图(线条、矩形)、文字输出、位图绘制。除了GDI的基本操作之外,还讲了一些随机数的有关概念和函数。
GDI,即Graphics Device Interface,它是Windows图形显示程序与物理设备(显示屏)之间的桥梁,在程序中,物理设备被简化为DC,程序只需直接对DC进行操作即可。
一.DC的基本概念
DC,即Device Context。在计算机上,如果要进行绘图,那么Device就是屏幕,而Device Context就是屏幕上的显示层,程序中显示的任何操作都是在DC上实现的。如果程序要利用GDI进行绘图,首先要获得DC的句柄,当绘图完成之后需要释放DC的句柄。
获取HDC有两种方式,即BeginPaint()和GetDC():
1. BeginPaint():
BeginPaint()有两个参数,第一个为窗口句柄,第二个为创建的PAINTSTRUCT的指针,即BeginPaint(hwnd,&PAINTSTRUCT)。BeginPaint()返回HDC,当BeginPaint()完成后,由EndPaint()释放句柄完成。
g_hdc = BeginPaint(hwnd, &PAINTSTRUCT);
Game_Paint(hwnd);
EndPaint(hwnd, &PAINTSTRUCT);
2. GetDC():
GetDC(hwnd)返回HDC,完成后由ReleaseDC(hwnd, g_hdc)释放句柄。
g_hdc = GetDC(hwnd);
Game_Paint(hwnd);
ReleaseDC(hwnd, g_hdc);
二、GDI基本绘图
GDI基本绘图包括三个步骤:创建绘图工具(Create***)-> 选中工具(SelectObject)->删除工具(DeleteObject)
绘图工具包括画笔(HPEN)、画刷(HBRUSH)。
当选中工具时,需注意在同一设备环境中,只能同时存在一种画笔对象或画刷对象,当已存在时继续选中就只会选中最新的对象,之前所创建的画笔或画刷对象会被替换掉。
绘制线条通过LineTo和MoveToEX两个函数实现。MoveToEx(g_hdc, x1, y1, LPOINT)将画笔当前点移动到(x1,y1)处,而LineTo(g_hdc, x2, y2)将从画笔当前点到(x2,y2)画出一条直线(即从(x1,y1)到(x2,y2)的直线)。
绘制矩形通过Rectangle(g_hdc, x1, y1, x2, y2)函数实现,矩形坐上角坐标为(x1,y1),右下角坐标为(x2,y2)。当绘制矩形后,如果通过SelectObject()选中画刷后,会在矩形内用画刷填充满矩形。
附上对应代码:
首先定义相关的句柄:
HPEN g_Hpen[7] = { 0 };//定义画笔句柄的数组
HBRUSH g_Brush[7] = { 0 };//定义画刷句柄的数组
int g_iPenStyle[7] = { PS_SOLID, PS_DOT, PS_DASH, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL,
PS_INSIDEFRAME };//定义画笔样式数组并初始化
int g_iBrushStyle[7] = { HS_VERTICAL, HS_HORIZONTAL, HS_CROSS, HS_DIAGCROSS, HS_FDIAGONAL,
HS_BDIAGONAL };//定义画刷样式数组并初始化
接下来是Game_Init()、Game_Paint()和Game_CleanUp():
BOOL Game_Init(HWND hwnd)
{
g_hdc = GetDC(hwnd);//获取DC
//srand((unsigned)time(NULL));
srand(timeGetTime());//初始化时间种子
//随机初始化画笔和画刷的颜色值
for (int i = 0; i <= 6; i++)
{
g_Hpen[i] = CreatePen(g_iPenStyle[i], 1, RGB(rand() % 256, rand() % 256, rand() % 256));
if (i == 6)
//g_Brush[i] = CreateSolidBrush(RGB(rand() % 256));
g_Brush[i] = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256));
else
g_Brush[i] = CreateHatchBrush(g_iBrushStyle[i], RGB(rand() % 256, rand() % 256, rand() % 256));
}
Game_Paint(hwnd);
ReleaseDC(hwnd, g_hdc);
return TRUE;
}
VOID Game_Paint(HWND hwnd)
{
int y = 0;//定义一个y坐标
//一个for循环,用7种不同的画笔绘制线条
for (int i = 0; i <= 6; i++)
{
y = (i + 1) * 70;
SelectObject(g_hdc, g_Hpen[i]);//选择对应的画笔
MoveToEx(g_hdc, 30, y, NULL);//光标移动到坐标(30,y)处
LineTo(g_hdc, 100, y);//从(30,y)到(100,y)绘制线条
}
int x1 = 120;//定义两个x坐标
int x2 = 190;
//用7种不同的画刷填充矩形
for (int i = 0; i <= 6; i++)
{
SelectObject(g_hdc, g_Brush[i]);//选择对应的画刷
Rectangle(g_hdc, x1, 70, x2, y);//画出一个封闭的矩形,矩形左上角为(x1,50),右下角为(x2,y)
x1 += 90;
x2 += 90;
}
}
BOOL Game_CleanUp(HWND hwnd)
{
for (int i = 0; i <= 6; i++)
{
DeleteObject(g_Hpen[i]);
DeleteObject(g_Brush[i]);
}
return true;
}
三、文字输出
文字输出主要有三种方法,即TextOut()、DrawText()、DrawTextEX(),一般选中TextOut()即可。
输出的文字主要有三种属性,均可以设置:
通过SetTextColor(g_hdc, RGB())设置文字颜色。
通过SetBkMode(g_hdc, iBkMode)设置文字背景颜色。
通过CreateFont(***)设置文字字体。
文字输出的Game_Init()、Game_Paint()和Game_CleanUp():
BOOL Game_Init(HWND hwnd)
{
g_hdc = GetDC(hwnd);
Game_Paint(hwnd);
ReleaseDC(hwnd, g_hdc);
return TRUE;
}
VOID Game_Paint(HWND hwnd)
{
HFONT hFont = CreateFont(30, 0, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, L"字体");//创建一种字体
SelectObject(g_hdc, hFont);//将字体选入设备环境中
SetBkMode(g_hdc, TRANSPARENT);//设置文字输出背景为透明
wchar_t text1[] = L"Hello,World!";
wchar_t text2[] = L"Hello, Game!";
wchar_t text3[] = L"Hello, GTA5!";
srand(timeGetTime());
SetTextColor(g_hdc, RGB(rand() % 256, rand() % 256, rand() % 256));//随机设置文字颜色
TextOut(g_hdc, 30, 150, text1, wcslen(text1)); //输出文字
SetTextColor(g_hdc, RGB(rand() % 256, rand() % 256, rand() % 256));
TextOut(g_hdc, 30, 180, text2, wcslen(text2));
SetTextColor(g_hdc, RGB(rand() % 256, rand() % 256, rand() % 256));
TextOut(g_hdc, 30, 210, text3, wcslen(text3));
DeleteObject(hFont);
}
BOOL Game_CleanUp(HWND hwnd)
{
return TRUE;
}
四、位图绘制
位图绘制主要有四个步骤:
1. 将位图加载到位图句柄中(LoadImage())。
g_bitmap = (HBITMAP)LoadImage(NULL, L"Naruto.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
2. 建立与屏幕DC相容的内存DC(CreateCompatibleDC())。
g_mdc = CreateCompatibleDC(g_hdc);
3. 将位图对象选中到内存DC中(SelectObject())。
SelectObject(g_mdc, g_bitmap);
4. 将贴图由内存DC贴到屏幕DC中(BitBlt())。
BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
最后附上加载位图的Game_Init()、Game_Paint()和Game_CleanUp():
BOOL Game_Init(HWND hwnd)
{
g_hdc = GetDC(hwnd);
//位图绘制步骤一:加载位图
g_bitmap = (HBITMAP)LoadImage(NULL, L"Naruto.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
//步骤四:建立相容DC
g_mdc = CreateCompatibleDC(g_hdc);
Game_Paint(hwnd);
ReleaseDC(hwnd, g_hdc);
return TRUE;
}
VOID Game_Paint(HWND hwnd)
{
//步骤三:选用位图对象
SelectObject(g_mdc, g_bitmap);
//步骤四:进行贴图
BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
}
BOOL Game_CleanUp(HWND hwnd)
{
DeleteObject(g_bitmap);
DeleteDC(g_mdc);
return TRUE;
}