失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 重温WIN32 API ------ 窗口上绘制位图文件

重温WIN32 API ------ 窗口上绘制位图文件

时间:2023-02-23 03:47:23

相关推荐

重温WIN32 API ------ 窗口上绘制位图文件

1 基本思路

做界面仿真时,经常需要在窗口上贴图,随着图片数量的增多,通过资源文件中添加位图的方式会变得越来越不可控。所以本着“资源与程序分离“的原则,还是使用外部位图文件更加清晰明了。

那么如何管理位图的贴图位置呢?如果写死到程序代码中,则又会导致耦合行过高的问题。容易想到解决方法有两个,一是使用一个单独的xml文件来记录图片文件名称和贴图位置的关系,二是直接把贴图位置信息包含进位图文件的文件名中。本文采用更加简单的后者,位图文件名格式规范为:description_xxx-yyy.bmp ,其中xxx为贴图时相对于所在窗口的x坐标,yyy为贴图时相对于所在窗口的y坐标,例如:发动机按钮_100-200.bmp,表示贴图时,目的坐标点为(100,200)。

至于贴图的实现,考虑到只需要支持bmp一种格式即可,所以采用GDI库完成。考虑到一个位图文件可能会被贴图多次(例如刷新的时候),所以实现时没有直接SetDIBitsToDevice(),而是首先把DIB通过CreateDIBitmap()转化为DDB,然后保存这个DDB,这样以后每次贴图时,只需要BitBlt()这个DDB就可以了,提高了效率。

2 代码实现

BitmapHelper.h

#pragma once/********************************************************************************BitmapHelper 贴图助手功能描述:根据位图文件名,把位图文件读入并贴到指定窗口,为提高效率对象内部一直保存读入内存的BITMAP,所以只在第一次贴图时需要从外部文件读取。使用说明:每一个位图文件对应一个BitmapHelper类对象。使用样例:BitmapHelper *pBmp = new BitmapHelper(L"D:\\风景_100-300.bmp");pBmp->ShowOnWindow(this->m_hWnd);delete pBmp; // 程序结束或不再需要这个位图时,删除********************************************************************************/class BitmapHelper{public:BitmapHelper(TCHAR* file);~BitmapHelper();protected:TCHAR fileName[256] ; // 位图文件名HBITMAP hBitmap;// 位图句柄int desX; // 目的x坐标int desY; // 目的y坐标protected:void ShowOnWindow(HWND hwnd, int x, int y); // 在指定窗口上显示public:HBITMAP CreateBitmapObjectFromDibFile(HDC hdc); //从文件中获取DDBvoid ShowOnWindow(HWND hwnd);void ShowOnDevice(HDC dc, int x, int y);};

BitmapHelper.cpp

#include "stdafx.h"#include "BitmapHelper.h"#include "string.h"BitmapHelper::BitmapHelper(TCHAR* file){this->hBitmap = NULL;this->desX = -9999;this->desY = -9999;::StrCpyNW(this->fileName, file, 256);this->fileName[255] = TEXT('\0');}/*功能:从位图文件创建DDB参数: hdc 设备DC返回值: DDB句柄,错误返回NULL*/HBITMAP BitmapHelper::CreateBitmapObjectFromDibFile(HDC hdc){BITMAPFILEHEADER* pbmfh = NULL;HANDLE hFile = NULL;DWORD dwFileSize = 0;hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);if (hFile == INVALID_HANDLE_VALUE){return NULL;}dwFileSize = GetFileSize(hFile, NULL);pbmfh = (BITMAPFILEHEADER*)malloc(dwFileSize);if (pbmfh == NULL){CloseHandle(hFile);return NULL;}DWORD dwBytesRead = 0;BOOL bSuccess = ::ReadFile(hFile, pbmfh, dwFileSize, &dwBytesRead, NULL);::CloseHandle(hFile);// 验证文件确实是位图文件if (!bSuccess || dwBytesRead != dwFileSize || pbmfh->bfType != *(WORD*) "BM" || pbmfh->bfSize != dwFileSize){free(pbmfh);return NULL;}HBITMAP hBitmap = ::CreateDIBitmap(hdc,(BITMAPINFOHEADER*)(pbmfh + 1),CBM_INIT,(BYTE*)pbmfh + pbmfh->bfOffBits,(BITMAPINFO*)(pbmfh + 1),DIB_RGB_COLORS);free(pbmfh);return hBitmap;}/*功能:在指定的设备上显示图片参数:hdc 设备DC, (x,y)为目的左上角坐标*/void BitmapHelper::ShowOnDevice(HDC hdc, int x, int y){if (this->hBitmap == NULL){this->hBitmap = this->CreateBitmapObjectFromDibFile(hdc);}if (this->hBitmap != NULL){BITMAP bitmap;::GetObject(this->hBitmap, sizeof(BITMAP), &bitmap);HDC hdcMem = ::CreateCompatibleDC(hdc);::SelectObject(hdcMem, this->hBitmap);::BitBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);::DeleteDC(hdcMem);}}/*功能:在指定窗口上显示位图参数:hwnd 窗口句柄, (x,y) 目的左上角坐标*/void BitmapHelper::ShowOnWindow(HWND hwnd, int x, int y){if (this->hBitmap == NULL){HDC hdc = ::GetDC(hwnd);this->hBitmap = this->CreateBitmapObjectFromDibFile(hdc);::ReleaseDC(hwnd, hdc);}if (this->hBitmap != NULL){BITMAP bitmap;::GetObject(this->hBitmap, sizeof(BITMAP), &bitmap);HDC hdc = ::GetDC(hwnd);HDC hdcMem = ::CreateCompatibleDC(hdc);::SelectObject(hdcMem, this->hBitmap);::BitBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);::DeleteDC(hdcMem);::ReleaseDC(hwnd, hdc);}}/*功能:根据文件名解析位置显示位图文件到指定窗口参数: hwnd 目的窗口说明: 位图文件命名规范 name_xxx-yyy.bmp*/void BitmapHelper::ShowOnWindow(HWND hwnd){// 解析文件名if (this->desX == -9999){int i = 0;int indexLast_ = 0; //最后一个_,表示坐标的开始int indexLastDot = 0; //最后一个.,表示扩展名的开始int indexSep = 0; // 坐标分割标志-int n = wcslen(this->fileName);for (i = n-1; i >=0; i--){if (this->fileName[i] == L'_'){break;}}indexLast_ = (i == 0 ? -1 : i); // -1 表示没有目录部分for (i = n - 1; i >= 0; i--){if (this->fileName[i] == L'.'){break;}}indexLastDot = (i == 0 ? n : i); // n表示没有扩展名部分int xyStart = indexLast_ + 1; // 坐标起始位置int xyEnd = indexLastDot - 1;// 坐标结束位置for (i = xyStart; i <= xyEnd; i++){if (this->fileName[i] == L'-'){break;}}indexSep = i == xyEnd ? -1 : i; // -1 表示没有找到-if (n==0 || indexSep==-1) {this->desX = 0;this->desY = 0;}else{TCHAR s_x[10];int count = indexSep - xyStart;wcsncpy_s(s_x, 10, this->fileName+xyStart, count);s_x[count] = L'\0';this->desX = _wtoi(s_x);WCHAR s_y[10];count = xyEnd - indexSep;wcsncpy_s(s_y, 10, this->fileName+indexSep+1, count);s_y[count] = L'\0';this->desY = _wtoi(s_y);}}this->ShowOnWindow(hwnd, this->desX, this->desY);}BitmapHelper::~BitmapHelper(){if (this->hBitmap != NULL) // 清理位图资源{::DeleteObject(this->hBitmap);}}

如果觉得《重温WIN32 API ------ 窗口上绘制位图文件》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。