ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

win32 - 绘图

2022-08-02 09:04:17  阅读:138  来源: 互联网

标签:ps int hwnd DC win32 HDC hdc 绘图


绘图编程

1. 绘图基础

绘图设备 DC (Device Context),绘图上下文 / 绘图描述表。os提供的绘画工具,由它代用户进行绘画。

HDC:DC句柄,表示绘图设备

GDI:Windows graphics device interface(Win32 提供的绘图API)

颜色:RGB 三原生

每个颜色用3个字节保存24位保存 0~2^24-1。
曾经使用16位:最低5位红色,中间5位绿色,后6位蓝色。
还有使用32位:前3个8位代表RGB,最后8位代表透明度,用于三维图形开发。

  • 颜色使用:COLORREF类 - 实际为 DWORD。例如:COLORREF nColor = 0
  • 赋值使用RGB宏:nColor = RGB(0, 0, 255);
  • 获取RGB:GetRValue / GetGValue / GetBValue 。 BYTE nRed = GetRValue(nColor);

 

获得绘图设备

WINUSERAPI
HDC
WINAPI
BeginPaint(
    _In_ HWND hWnd,
    _Out_ LPPAINTSTRUCT lpPaint);

绘图操作

 

释放绘图设备

WINUSERAPI
BOOL
WINAPI
EndPaint(
    _In_ HWND hWnd,
    _In_ CONST PAINTSTRUCT *lpPaint);

2. 基本图形绘制

画点

// 设置定点的颜色
WINGDIAPI COLORREF WINAPI SetPixel(
    _In_ HDC hdc,  // dc句柄
    _In_ int x,    // X 坐标
    _In_ int y,    // Y 坐标
    _In_ COLORREF color // 设置的颜色
); // 返回原来的颜色

WM_PAINT 消息中调用函数绘制图形:

void OnPaint(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	for (int i = 50; i < 100; i++)
	{
		for (int j = 50; j < 100; j++)
		{
			SetPixel(hdc, i, j, RGB(i, 0, j));
		}
	}

	EndPaint(hwnd, &ps);
}

画线

需要配合使用

  1. MoveToEx:指明窗口当前点
  2. LineTo:从窗口当前点到指定点绘制一条直线,同时也会调用 MoveToEx
  3. 当前点:上一次绘图时最后一点,初始值为 ( 0, 0 ) 点。每个窗口都有。

在处理 WM_PAINT 消息内调用:

void DrawLine(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	MoveToEx(hdc, 50, 50, NULL);
	LineTo(hdc, 300, 300);

	EndPaint(hwnd, &ps);
}

封闭图形

能够用画刷填充的图形 Rectangle / Ellipse

void DrawRect(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	Rectangle(hdc, 100, 100, 300, 300);
	Ellipse(hdc, 100, 100, 300, 300);

	EndPaint(hwnd, &ps);
	
}

3. GDI 绘图对象

使用Paint画图时只能画出黑色

画笔

线的颜色、线型(实线、虚线、点线)、线粗
HPEN 画笔句柄

1. 创建画笔
// 创建成功返回句柄
WINGDIAPI 
HPEN
WINAPI CreatePen( 
    _In_ int iStyle,    // 画笔样式
    _In_ int cWidth,    // 画笔的粗细
    _In_ COLORREF color // 画笔颜色
);
// 画笔样式
PS_SOILD  实心线,第二个参数可支持多个像素宽,其他线型只能时一个像素宽



2. 将画笔应用到DC中
// 将画笔送给绘图设备。返回旧GDI绘图对象句柄,注意:保存原DC当中的画笔
// 可以形象的理解为用一个新的GDI绘图对象从DC那里交换旧的GDI绘图对象。
WINGDIAPI 
HGDIOBJ 
WINAPI 
SelectObject(
    _In_ HDC hdc,   // 绘图设备句柄
    _In_ HGDIOBJ h  // GDI 绘图对象句柄,画笔句柄。HPEN 是 HGDIOBJ 的一种
);



3. 绘图


4. 取出DC中的画笔
将原来的画笔,使用SelectObject函数,放入DC中,交换出我们创建的画笔


5. 释放画笔
WINGDIAPI 
BOOL 
WINAPI 
DeleteObject( 
    _In_ HGDIOBJ ho  // GDI 绘图句柄,画笔句柄
);
只能删除不被DC使用的画笔,在释放前,必须将画笔从DC中取出。

例子,在 WM_PAINT 消息中处理:

void Draw(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	HGDIOBJ hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
	HGDIOBJ oldGDI = SelectObject(hdc, hPen);

	Rectangle(hdc, 100, 100, 300, 300);

	hPen = SelectObject(hdc, oldGDI); // 因为这个画笔是在这个函数中创建的,所以亦可以不接收
	DeleteObject(hPen);

	EndPaint(hwnd, &ps);
	
}


使用 CreatePen(PS_DASH, 1, RGB(255, 0, 0))时第二个参数必须为1,如果为其他值,这个画笔失效。

画刷

给封闭图形填充颜色、图案。HBRUSH 画刷句柄。

使用:

  1. 创建画刷
    CreateSoliBrush  CreateHatchBrush
  2. 将画刷应用到DC中
    SelectObject
  3. 绘图
  4. 将画刷从DC中取出
    SelectObject
  5. 删除画刷
    DeleteObje

示例:

void Draw(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0));
	HGDIOBJ hOldBrush = SelectObject(hdc, hBrush); // 默认有一把白色画刷

	Rectangle(hdc, 100, 100, 300, 300);

	SelectObject(hdc, hOldBrush);
	DeleteObject(hBrush);

	EndPaint(hwnd, &ps);
}

void Draw(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	//HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0));
	HBRUSH hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));
	HGDIOBJ hOldBrush = SelectObject(hdc, hBrush); // 默认有一把白色画刷

	Rectangle(hdc, 100, 100, 300, 300);

	SelectObject(hdc, hOldBrush);
	DeleteObject(hBrush);

	EndPaint(hwnd, &ps);
}

透明画刷

通常情况下希望图形填充颜色与背景相同。

通过 GetStockObject 获取系统维护的画刷、画笔等。如无需画刷,可通过 NULL_BRUSH NULL_PEN 获取不填充的画刷、画笔。这个函数返回的画刷无需 DeleteObject

void Draw(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);

	HGDIOBJ hBrush = GetStockObject(NULL_BRUSH);
	HGDIOBJ hOldObj = SelectObject(hdc, hBrush);
	HGDIOBJ hPen = GetStockObject(NULL_PEN);
	HGDIOBJ hOldPen = SelectObject(hdc, hPen);

	Rectangle(hdc, 100, 100, 300, 300);

	SelectObject(hdc, hOldObj);
	SelectObject(hdc, hOldPen);
	EndPaint(hwnd, &ps);
}

 

位图

1. 位图绘制

位图相关:

  • 光栅图形:记录图像中每一点的颜色等信息(常见)。bitmap 就是严格记录了每一个点的信息。
  • 矢量图形:记录图像算法、绘图指令等(用于图谱分析、科学计算等)

HBITMAP:位图句柄

位图使用:

  1. 在资源中添加位图资源——兼具 GDIOBJ资源 的特点
     
  2. 从资源中加载位图 LoadBitmap
    HBITMAP
    LoadBitmapA(
        _In_opt_ HINSTANCE hInstance,
        _In_ LPCSTR lpBitmapName
    );
  3. 创建一个与当前DC相匹配的DC(内存DC)
    当前DC在屏幕上绘画
    内存DC在内存中绘画
    HDC CreateCompatibleDC( _In_opt_ HDC hdc); // 传入当前DC,为NULL时代表屏幕DC;在内存构建一个虚拟地区,并返回内存DC用于在虚拟地区绘画
  4. 将bitmap放入匹配的DC中,SelectObject
    将bitmap放入内存中后,内存里会立即画出图片。
  5. 成像(1:1 比例 )
    将内存中的图像成像到屏幕上
    WINGDIAPI BOOL  WINAPI BitBlt( 
        _In_ HDC hdc,  // 目标DC,一般为“当前DC”
        _In_ int x,    // 目的左上X坐标
        _In_ int y,    // 目的左上Y坐标,在窗口的什么位置成像
        _In_ int cx,   // 目标宽度
        _In_ int cy,   // 目标高度,在窗口中开辟多大空间用于成像
        _In_opt_ HDC hdcSrc,   // 源DC,“内存DC”
        _In_ int x1,   // 源左上X坐标
        _In_ int y1,   // 源左上Y坐标,从内存中图像的哪个位置开始成像
        _In_ DWORD rop // 成像方法 SRCCOPY:原样成像
    );
    // 当目标区域小于原图时,只能显示部分图像。

    缩放成像,缩小或放大:由“目标DC中高宽”和“源DC高宽”的比例决定

    BOOL StretchBlt(
        _In_ HDC hdcDest, // 目的DC
        _In_ int xDest,   // X
        _In_ int yDest,   // Y
        _In_ int wDest,   // 目标宽
        _In_ int hDest,   // 目标高
        _In_opt_ HDC hdcSrc,  // 源DC
        _In_ int xSrc,    // X
        _In_ int ySrc,    // Y
        _In_ int wSrc,    // 源DC宽
        _In_ int hSrc,    // 源DC高  这两个参数指定成像多大区域
        _In_ DWORD rop
    );
  6. 取出位图
    SelectObject
  7. 释放位图
    DeleteObject
  8. 释放匹配的DC
    DeleteDC

前2步与资源操作类似,第345步与绘图类似。

void Draw(HWND hwnd)
{
	PAINTSTRUCT ps = { 0 };
	HDC hdc = BeginPaint(hwnd, &ps);
	//1. 添加资源

	//2. 加载 bitmap
	HBITMAP hBitmap =  LoadBitmap(g_hInstance, (LPCWSTR)IDB_BITMAP1);
	
	//3. 创建内存DC,并构建虚拟区域,在内存DC中画图
	HDC hMemDC = CreateCompatibleDC(hdc);

	//4. 将位图送给内存DC,内存DC在虚拟区域画出
	HGDIOBJ hOldGdiObj = SelectObject(hMemDC, hBitmap);

	//5. 将虚拟区域的图像成像到窗口中
	BitBlt(hdc, 50, 50, 48, 48, hMemDC, 0, 0, SRCCOPY);
	StretchBlt(hdc, 0, 0, 24, 24, hMemDC, 0, 0, 48, 48, SRCCOPY);

	//6.
	SelectObject(hMemDC, hOldGdiObj);
	//7.
	DeleteObject(hBitmap);
	//8.
	DeleteDC(hMemDC);

	EndPaint(hwnd, &ps);
}

  1:1 成像 , 缩放到原来一半

 

 

文本绘制

TextOut // 功能最弱,不能换行,不能对齐

int DrawTextA(
    _In_ HDC hdc,      // DC句柄
    LPCSTR lpchText,   // 字符串
    _In_ int cchText,  // 字符数
    _Inout_ LPRECT lprc,  // 绘制文字的矩形框
    _In_ UINT format   // 绘制方式
);

 示例:

LRESULT CALLBACK WnProc(
	HWND hwnd,
	UINT msg,
	WPARAM wparam,
	LPARAM lparam)
{
	switch (msg)
	{
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hwnd, &ps);

		TCHAR szText[] = TEXT("12345678901234567890 qwert asdf");
		TextOut(hdc, 100, 100, szText, lstrlen(szText));

		Rectangle(hdc, 100, 150, 200, 200);

		RECT rc;
		rc.left = 100;
		rc.top = 150;
		rc.right = 200;
		rc.bottom = 200;
		
        // DT_CENTER 不能与DT_WORDBREAK 一起使用。前者只适用于DT_SINGLELINE,一定靠顶端
		DrawText(hdc, szText, lstrlen(szText), &rc, DT_WORDBREAK);

		EndPaint(hwnd, &ps);
		break;
	}
	default:
		break;
	}
	return DefWindowProc(hwnd, msg, wparam, lparam);
}

美化

颜色

  • SetTextColor
  • SetBkColor  背景色默认白色,只适用于 OPAQUE 模式
  • SetBkMode (OPAQUE / TRANSPARENT)  文字背景模式,只有这两种
    • OPAQUE 默认的不透明模式
    • TRANSPARENT 透明模式
SetTextColor(hdc, RGB(255, 0, 0));
SetColor(hdc, RGB(0, 255, 0));
SetBkMode(hdc, TRANSPARENT);

 字体

 windows常用TrueType字体。字体名:标识字体类型。HFONT:字体句柄。

  1. 创建字体
    HFONT CreateFontA( 
        _In_ int cHeight,     // 字体高
        _In_ int cWidth,      // 字体宽
        _In_ int cEscapement, // 字符串倾斜角度,
        _In_ int cOrientation,// 字符旋转角度,以x轴为中心向里或向外旋转
        _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_opt_ LPCSTR pszFaceName  // 字体名称
    );
  2. 应用字体到DC
    SelectObject
  3. 绘制文字
    DrawText / TextOut
  4. 取出字体
    SelectObject
  5. 删除字体
    DeleteObject

 

case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hwnd, &ps);

		HFONT hFont = CreateFont(30, 0, 45, 0, 900, 1, 1, 1, GB2312_CHARSET, 0, 0, 0, 0, L"黑体");
		HGDIOBJ hOldObj = SelectObject(hdc, hFont);

		TCHAR szText[] = TEXT("12345678901234567890 qwert asdf");
		TextOut(hdc, 100, 100, szText, lstrlen(szText));

		SelectObject(hdc, hOldObj);
		DeleteObject(hFont);  // 字体占用内存大,一定记得释放
		EndPaint(hwnd, &ps);
		break;
	}

 

标签:ps,int,hwnd,DC,win32,HDC,hdc,绘图
来源: https://www.cnblogs.com/zhh567/p/16535646.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有