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 ------ 窗口上绘制位图文件相关推荐

  1. qt整个窗口上绘制矩形与在窗口的子控件上绘制矩形

    引言 创建一个基于QDialog的项目,自动生成ui文件,此时再添加新文件,创建一个基于QWidget的ui类,此类具有自定义标题栏,让该自定义类显示在窗口Dialog上,一开始具有红色的边框线,且四 ...

  2. PyQt5-在窗口上绘制文本 QPainter

    PyQt5-在窗口上绘制文本 QPainter #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2021/6/3 19:46 # @Au ...

  3. 重温WIN32 API ------ 最简单的Windows窗口封装类

    1 开发语言抉择 1.1 关于开发Win32 程序的语言选择 C还是C++ 在决定抛弃MFC,而使用纯Win32 API 开发Window桌面程序之后,还存在一个语言的选择,这就是是否使用C++.C+ ...

  4. Win32 API、VC++、C# 文件操作函数的初步比较

    一 C# File.ReadAllText(FilePath) : 一次将文本内容全部读完, File.ReadAllLines: 该方法返回一个字符串数组.每一行都是一个数组元素. string[] ...

  5. Win32 API 窗口版本转换度分秒为小数

    经纬度的度分秒和小数之间转换是做GIS时常用的:下面实现一个Win32 API 版本度分秒转换为小数: 与此网站对比: http://www.gzhatu.com/du2dfm.html 使用VC++ ...

  6. win7抓取计算机窗口存于位图文件,Win7系统电脑如何截图并保存?

    在我们日常使用电脑的过程中,总是能够看到一些好看的图片或者精彩图文对话,此时我们可以利用截图功能将这个内容截图保存下来,不过现在有个难题就是不知道电脑如何截图,其实电脑截图很简单的,下面就给大家介绍多 ...

  7. 窗口非客户区绘制位图与设计

    原文:http://www.haogongju.net/art/1891934 首先介绍在指定区域绘制位图 为了能够在指定的区域中输出位图,需要使用设备上下文CDC类的StretchBlt方法.由于我 ...

  8. java 基础api实现上传,上传文件到7牛云存储的java api一个简单的demo实现

    最近在做一个项目,需要用到云存储,项目用的是七牛云.现在将项目过程中关于调用七牛云平台的java api来上传本地文件到七牛云空间的一个简单的demo展示给大家,希望对同样再用七牛云的童鞋们有所帮助. ...

  9. Win32 API 打印

    重温 Win32 API ----- 截屏指定窗口并打印 http://blog.csdn.net/smstong/article/details/42082039 朋友说在一个VC++6.0开发的项 ...

最新文章

  1. cocoapods更新
  2. 0 到 1 的过往,1 到 10 的未来 | 智源两周年,开启新篇章
  3. 试玩UML(User Mode Linux)
  4. 在myeclipse当中使用正则表达式去除单行注释
  5. 爬取广州所有停车场数据(Python)(并行加速版本)
  6. QT使用之 手指滑动 | 物理惯性继续滑动动画的实现,根据不同速度实现不同动画效果
  7. 剑指offer---包含min函数的栈
  8. 思科ACL阻止勒索病毒
  9. 计算机课玩的小游戏怎么找,能够回味电脑课的小游戏是什么 怎么制作这两个小游戏...
  10. 解决 Electron 包下载太慢问题
  11. 腾讯广告的多媒体AI技术实战
  12. 装饰器补充、三元表达式、生成式、匿名函数
  13. ArcGIS Server(详细介绍)转
  14. java打印等腰三角形_为什么大家都说Java中只有值传递?
  15. GPS经纬度坐标转UTM坐标(c++)
  16. 看大神如何玩转微信小程序日历插件?
  17. xmlspy php,XML Spy实例代码详解(图)
  18. CCRC信息安全服务资质--风险评估申请
  19. 深入浅出golang的chan
  20. VB 对数据库access的模糊查询代码

热门文章

  1. 基于水平集LBF模型的图像边缘轮廓分割凸优化 - Split Bregman分裂布雷格曼算法的最优解
  2. Redis缓存穿透、击穿、雪崩面试题详解
  3. 接地电阻测试仪使用方法讲解
  4. python位运算符的用法
  5. 一起DIY四轴飞行器(一)项目简介
  6. uuid php,php生成uuid介绍
  7. SpringBoot实现证书License的授权和验证
  8. 火爆全网的“数字人”,到底是个啥?
  9. 研究生新生培训第二周:卷积神经网络基础
  10. 计算机报名照片怎么在线修图