字符界面的基本单位是字符。
图形界面的基本单位是像素。
像素:px,表示一个点。
绘图与贴图的消息处理: WM_PAINT
消息。
当然你也可以指定 Timer
计时器来每隔多长时间刷新一次。
首先要获取HDC:
HDC GetDC(
[in] HWND hWnd
);
检索DC的窗口句柄,并且返回在指定窗口工作的DC句柄。
ReleaseDC
HDC的释放:
ReleaseDC(hwnd, hdc);
SetPixel
来绘制像素点。
COLORREF SetPixel(
[in] HDC hdc,
[in] int x,
[in] int y,
[in] COLORREF color
);
绘制一条线:
//绘制像素点
for (int i = 1; i <= 100; i++) {
SetPixel(hdc, 100 + i, 100, RGB(255, 0, 0));
}
从 x = 100 − 200 , y = 100 x=100-200, y=100 x=100−200,y=100 的位置绘制了100个像素点,即绘制了一条线。
MoveToEx
来更新当前的焦点坐标:
BOOL MoveToEx(
[in] HDC hdc,
[in] int x,
[in] int y,
[out] LPPOINT lppt
);
LineTo
来绘制一条线的路径:
BOOL LineTo(
[in] HDC hdc,
[in] int x,
[in] int y
);
参数同样需要指定HDC与到达的坐标。
示例:来绘制一个简单的三角形:
//绘制像素点
for (int i = 1; i <= 100; i++) {
SetPixel(hdc, 100 + i, 100, RGB(255, 0, 0));
}
POINT oldPos{};
MoveToEx(hdc, 200, 100, NULL);
LineTo(hdc, 300, 300);
//保存(300,300)的位置,并且移动到(100,100)的位置
MoveToEx(hdc, 100, 100, &oldPos);
//画线到(300,300)的位置
LineTo(hdc, oldPos.x, oldPos.y);
//形成一个三角形
解释:
当然,我们这样做只是为了测试这几个函数的功能,一定还有其他的更加简便的方法。
我们首先需要创建画笔,然后需要将画笔交给画家,然后画家再画画,这是一个绘图的编程模型:
CreatePen
创建画笔:
HPEN CreatePen(
[in] int iStyle,
[in] int cWidth,
[in] COLORREF color
);
SelectObject
传递画笔给画家:
所谓画家其实就是HDC,即绘图设备上下文句柄。
HGDIOBJ SelectObject(
[in] HDC hdc,
[in] HGDIOBJ h
);
接下来就是绘图的过程了,我们只需要传递绘制指定图形的函数即可,这个例子中我绘制了一个矩形:
//1.自制画笔
HPEN pSolidPen1 = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN pDashPen1 = CreatePen(PS_DASH, 5, RGB(0, 255, 0));
//2.画笔交给画家
HGDIOBJ hOldObj = SelectObject(hdc, pSolidPen1);
MoveToEx(hdc,100, 100, NULL);
LineTo(hdc, 200, 200); //使用pSolidPen1来绘制
hOldObj = SelectObject(hdc, pDashPen1); //pOldObj保存pSolidPen1
LineTo(hdc, 300, 300); //使用pDashPen1来绘制
SelectObject(hdc, hOldObj); //使用pSolidPen1来绘制一个矩形
Rectangle(hdc, 100,200,150,300);
注意:我创建了两个画笔,然后分别使用这两种样式的画笔绘制了图形,我们只需要 SelectObject
选择相应的画笔即可,然后便可以直接绘制图形。
我们使用这个函数的返回值来保存当前的绘图画笔,然后再下面可以复原此次画笔。
使用画刷与画笔的过程是一样的,我们只需要:
CreateSolidBrush
HBRUSH CreateSolidBrush(
[in] COLORREF color
);
然后 SelectObject
可以传递画刷给画家(使得HDC为此画刷类型)。
接着绘图即可:
//1.自制画刷
HBRUSH hBrush1 = CreateSolidBrush(RGB(30, 30, 30));
HBRUSH hBrush2 = CreateSolidBrush(RGB(20, 210, 20));
//2.画刷给画家
SelectObject(hdc, hBrush1);
Rectangle(hdc, 10, 10, 100, 100);
SelectObject(hdc, hBrush2);
Ellipse(hdc, 200, 200, 400, 400);
贴图的过程比较复杂,大致可以分为如下的四个步骤:
我们需要获得HDC与HINSTANCE等信息,因此首先需要获得他们的信息:
HDC hdc = GetDC(hwnd); //获取HDC
HINSTANCE hInstanc = GetModuleHandle(NULL); //获取当前窗口的实例句柄
LoadImage
加载图片:
注意我们必须加载图片是 bmp 类型
HANDLE LoadImageA(
[in, optional] HINSTANCE hInst,
[in] LPCSTR name,
[in] UINT type,
[in] int cx,
[in] int cy,
[in] UINT fuLoad
);
**LR_LOADFROMFILE
**CreateCompatibleDC
创建兼容DC:
HDC CreateCompatibleDC(
[in] HDC hdc
);
SelectObject
图片选择到兼容DC,没错,又是这个函数。
BitBlt
兼容DC绘制到HDC:
这个函数完成的是从指定源设备上下文到目标设备上下文中的像素矩形对应的颜色数据的位块传输。
BOOL BitBlt(
[in] HDC hdc,
[in] int x,
[in] int y,
[in] int cx,
[in] int cy,
[in] HDC hdcSrc,
[in] int x1,
[in] int y1,
[in] DWORD rop
);
简单的操作示例:
//2. 贴图
void putImg(HWND hwnd) {
HDC hdc = GetDC(hwnd);
HINSTANCE hInstanc = GetModuleHandle(NULL);
//1. 加载图片
HANDLE p1 = LoadImage(hInstanc, L"img1.bmp", IMAGE_BITMAP, 207, 293, LR_LOADFROMFILE);
HANDLE p2 = LoadImage(hInstanc, L"img2.bmp", IMAGE_BITMAP, 299, 286, LR_LOADFROMFILE);
HANDLE p3 = LoadImage(hInstanc, L"img3.bmp", IMAGE_BITMAP, 265, 330, LR_LOADFROMFILE);
//2. 创建兼容DC
HDC hDc1 = CreateCompatibleDC(NULL);//与指定设备兼容的DC
HDC hDc2 = CreateCompatibleDC(NULL);
HDC hDc3 = CreateCompatibleDC(NULL);
//3. 把图片选择到兼容DC
SelectObject(hDc1, p1); //将对象选择到按指定的设备上下文中
SelectObject(hDc2, p2);
SelectObject(hDc3, p3);
//4. 从兼容DC绘制到HDC
BitBlt(hdc, 10, 10, 207, 293, hDc1, 0, 0, SRCCOPY);
BitBlt(hdc, 300, 10, 299, 286, hDc2, 0, 0, SRCCOPY);
BitBlt(hdc, 600, 10, 265, 330, hDc3, 0, 0, SRCCOPY);
}
效果如下所示:
我们使用上面的绘图方式是可以的,但是有可能会出现闪烁的情况,因此我们必须使用多级缓冲绘图,来解决这种问题,使得图片可以稳定加载。
步骤如下:
CreateCompatibleBitmap
:创建兼容位图:
HBITMAP CreateCompatibleBitmap(
[in] HDC hdc,
[in] int cx,
[in] int cy
);
其他的函数与上面基本一致。
TransparentBlt
是另一种绘图方式,与 BitBlt
是一样的:
BOOL TransparentBlt(
[in] HDC hdcDest,
[in] int xoriginDest,
[in] int yoriginDest,
[in] int wDest,
[in] int hDest,
[in] HDC hdcSrc,
[in] int xoriginSrc,
[in] int yoriginSrc,
[in] int wSrc,
[in] int hSrc,
[in] UINT crTransparent
);
BitBlt
的最后一个参数相同代码示例:
//2. 贴图
void putImg(HWND hwnd) {
HDC hdc = GetDC(hwnd);
HINSTANCE hInstanc = GetModuleHandle(NULL);
//1. 加载图片
HANDLE bk = LoadImage(hInstanc, L"bk.bmp", IMAGE_BITMAP, 1400, 770, LR_LOADFROMFILE);
HANDLE p1 = LoadImage(hInstanc, L"img1.bmp", IMAGE_BITMAP, 207, 293, LR_LOADFROMFILE);
HANDLE p2 = LoadImage(hInstanc, L"img2.bmp", IMAGE_BITMAP, 299, 286, LR_LOADFROMFILE);
HANDLE p3 = LoadImage(hInstanc, L"img3.bmp", IMAGE_BITMAP, 265, 330, LR_LOADFROMFILE);
//2. 创建兼容位图
HBITMAP hBit1 = CreateCompatibleBitmap(hdc, 1500, 770);
//3. 创建兼容DC
HDC hBk = CreateCompatibleDC(NULL);
HDC hDc1 = CreateCompatibleDC(NULL);
HDC hDc2 = CreateCompatibleDC(NULL);
HDC hDc3 = CreateCompatibleDC(NULL);
HDC hDst = CreateCompatibleDC(NULL); //最终的画布
//4. 兼容位图设置到兼容DC中
SelectObject(hDst, hBit1);
//5. 图片选择到兼容DC中
SelectObject(hBk, bk);
SelectObject(hDc1, p1);
SelectObject(hDc2, p2);
SelectObject(hDc3, p3);
//6. 每个兼容DC绘制到总的兼容DC中(总画布)
BitBlt(hDst, 0, 0, 1500, 770, hBk, 10, 10, SRCCOPY);
BitBlt(hDst, 0, 0, 207, 293, hDc1, 0, 0, SRCCOPY);
BitBlt(hDst, 250,10, 299, 286, hDc2, 0, 0, SRCCOPY);
BitBlt(hDst, 600, 10, 265, 330, hDc3, 0, 0, SRCCOPY);
//7. 最终兼容DC绘制到HDC
TransparentBlt(hdc, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN),
GetSystemMetrics(SM_CYFULLSCREEN),
hDst, 0, 0, 1500, 770, SRCCOPY);
}
CreateFont
来创建字体的样式:
参考链接:
CreateFontA 函数 (wingdi.h) - Win32 apps
HFONT CreateFontA(
[in] int cHeight,
[in] int cWidth,
[in] int cEscapement,
[in] int cOrientation,
[in] int cWeight,
[in] DWORD bItalic,
[in] DWORD bUnderline,
[in] DWORD bStrikeOut,
[in] DWORD iCharSet,
[in] DWORD iOutPrecision,
[in] DWORD iClipPrecision,
[in] DWORD iQuality,
[in] DWORD iPitchAndFamily,
[in] LPCSTR pszFaceName
);
然后便可以使用 TestOut
来创建文字了:
void text(HWND hwnd) {
HDC hdc = GetDC(hwnd);
HFONT hFont1 = CreateFont(48, 0, 0, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Impact"));
SelectObject(hdc, hFont1);
wchar_t buff[256] = L"这是一段文字";
TextOut(hdc, 100, 100, buff, wcslen(buff));
ReleaseDC(hwnd,hdc);
}