• win32 绘图


    原文网址:win32 - 绘图 - 某某人8265 - 博客园 (cnblogs.com)

    绘图编程

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

  • 相关阅读:
    小程序 页面跳转
    mybatis 字段类型Data相
    数据库的重命名
    validator js验证器
    git命令
    常用正则表达式
    Vuejs+elementUI项目,在进行打包时,要注意的问题
    多线程的sleep、yield、join用法及sleep与wait的区别
    跨域请求问题:CORS
    spring框架中用到了哪些设计模式
  • 原文地址:https://www.cnblogs.com/bruce1992/p/16649021.html
Copyright © 2020-2023  润新知