首页 > MFC中显示 .bmp格式的位图

MFC中显示 .bmp格式的位图

最近在看VisualC++ 图像处理的书籍,表示一直在从基础做起,今天就记录一个简单功能的实现,显示.bmp格式的位图。

首先需要理解的是窗口创建的过程包括两个步骤:首先擦除窗口的背景,然后在对窗口进行重新绘制。

一般而言,对于单文档或多文档的MFC程序,显示图像的代码要放在OnDraw函数之中。刚刚说过,窗口重绘时,要先将窗口的背景擦除,也就是发送WM_ERASEBKGND消息,然后用OnEraseBkgnd()函数处理这个消息,所以我们的显示图像的代码也可以放在这个函数之中。当然,这里只是为了实现显示位图这一个功能,在实际工程中,要根据实际情况,选择代码放置的地方。

下面先给出代码,然后一行一行地详细解释:

BOOL CLoadBitmapView::OnEraseBkgnd(CDC* pDC)

{

 // TODO: 在此添加消息处理程序代码和/或调用默认值

 //return FALSE;

 HBITMAP hBit;

 hBit=(HBITMAP) LoadImage(NULL,_T("D:\Axing.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); //载入图像

 CBitmap cBit;

 cBit.Attach(hBit);

 CDC MemDC;

 MemDC.CreateCompatibleDC(pDC); //创建与当前设备描述表相适应的内存DC

 BITMAP bitmap;

 cBit.GetBitmap(&bitmap);

 CBitmap *oldBit;

 oldBit=MemDC.SelectObject(&cBit);

 CRect rect;

 GetClientRect(&rect);

 pDC->BitBlt(100,100,rect.Width()/2.5,rect.Height(),&MemDC,0,0,SRCCOPY);

 return TRUE;

 //return CView::OnEraseBkgnd(pDC);

}

 

 

首先来解释一下HBITMAP、CBitmap、BITMAP三者之间的关系。

HBITMAP是图片的句柄,CBitmap是MFC定义的一个类,在这个类中对HBITMAP进行了封装,BITMAP则是一个结构体,这个结构体中保存着位图的各种信息(如宽度和高度等)。有三个函数是和这三个类型息息相关的。

第一个:Attach(),这个函数是CBitmap类的成员函数,作用就是将HBITMAP类型转换成CBitmap类型。我们在代码中会用到它。

第二个:GetBitmap(),这个函数也是CBitmap类的成员函数,作用就是获取位图的信息,并将位图的信息保存在BITMAP 结构指针中。

第三个:GetObject(),这个函数的作用就是,从HBITMAP句柄中获取BITMAP结构。

这三个函数的具体用法,详细说明在这里就不赘述了,用的时候可以百度一下很方便的。

 

我们先建立了一个HBITMAP类型的句柄,然后用LoadImage()函数来载入一个位图,并保存位图的句柄。之后,创建一个CBitmap类的对象,然后将HBITMAP转换成CBitmap对象(用Attach()函数)。之后用CReateCompatibleDC()函数,创建一个与当前设备上下文相兼容的内存DC。

问题来了,为什么要创建这个内存DC呢?

其实,这个内存DC的作用就是缓冲。如果需要对屏幕进行比较多的GUI操作,如果直接对屏幕DC进行操作,会导致同显示内存之间的过于频繁的数据交换,于是程序运行效率将受到严重影响。任何绘图的过程都是这样,要完成一幅图像的显示,总是在显示终端上依次绘制每个像素点,以形成完整的图像。我们在内存中虚拟一块画布(就是内存DC),绘图时仅仅对内存进行操作。待政府图像绘制完成时在整体复制到屏幕上,这样避免了外设和内存之间频繁的数据交换,程序的运行效率会提高很多。这就是使用CreateCompatibleDC()函数创建内存DC 的作用。

接着,我们将位图选入到内存DC中(MemDC.SelectObject(&cBit)),这一步也是相当重要的。因为当兼容的内存DC创建的时候,他的显示表面是标准的一个单色像素宽和单色像素高。在应用程可以使用内存DC进行绘图操作之前,必须将一个具有正确高度和宽度的位图,选入到内存DC中,这时内存设备上下文显示表面的大小就由当前选入的位图决定了。

之后CRect rect;GetClientRect(&rect);用于获取客户区。

最后用BitBlt()函数将内存DC中的内容复制到当前DC中,显示位图完毕。

这里要解释一下BitBlt函数,它的函数原型为:

BOOLBitBlt(int x,int y,int nWidth,int nHeight,CDC*pSrcDC,int xSrc,int ySrc,DWORDdwRop);

参数x、y表示目的DC(当前设备上下文)矩形区域的左上角坐标,nWidth,nHeight,表示矩形区域的宽和高,pSRCDC则是源DC(内存DC)的指针,xSrc和ySrc表示源DC矩形区域的左上角坐标。我们可以看到并没有参数表示源目的矩形区域的宽和高,这样,区域之间的复制只能是1:1的,所以当图像比较大时,只能显示图像的一部分。为了解决这个问题,可以用StretchBlt()函数,这个函数和BitBlt()函数的功能基本一致,只是可以对图像进行伸缩变换,这是因为在StretchBlt()函数中增加了两个参数,表示源DC矩形区域的大小。所以上面的代码可以改成

 pDC->StretchBlt(100,100,rect.Width()/2.5,rect.Height(),&MemDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);

这样就可以显示整张位图了。

 

转载于:https://www.cnblogs.com/qingergege/p/4964951.html

更多相关:

  • 草色新雨中, 松声晚窗里。之前我们学习 Power Query 都是用鼠标就完成了很多复杂的操作。虽然 PowerQuery 已经将大部分常用功能内置成到功能区。基本能完成我们大部分的报表自动化功能。但是总有些复杂的或者个性化的问题是开发团队没有预先想到的,这时我们就需要学习 M 语言。一、M 语言在哪里?M语言的函数公式有三个地...

  • 前言从2020年3月份开始,计划写一系列文档--《小白从零开始学编程》,记录自己从0开始学习的一些东西。第一个系列:python,计划从安装、环境搭建、基本语法、到利用Django和Flask两个当前最热的web框架完成一个小的项目第二个系列:可能会选择Go语言,也可能会选择Vue.js。具体情况待定,拭目以待吧。。。基本概念表达式表...

  • 1.1函数1.1.1什么是函数函数就是程序实现模块化的基本单元,一般实现某一功能的集合。函数名:就相当于是程序代码集合的名称参数:就是函数运算时需要参与运算的值被称作为参数函数体:程序的某个功能,进行一系列的逻辑运算return 返回值:函数的返回值能表示函数的运行结果或运行状态。1.1.2函数的作用函数是组织好的,可重复使用的,用来...

  • 原标题:基于Python建立深度神经网络!你学会了嘛?图1 神经网络构造的例子(符号说明:上标[l]表示与第l层;上标(i)表示第i个例子;下标i表示矢量第i项)单层神经网络图2 单层神经网络示例神经元模型是先计算一个线性函数(z=Wx+b),接着再计算一个激活函数。一般来说,神经元模型的输出值是a=g(Wx+b),其中g是激活函数(...

  • 在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重。小编刚开始学习的时候也会有这个感觉。不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个。今天小编就把常用的函数汇总一下,为大家能够能好的学习MySQL中的函数。MySQL常使用的函数大概有四类。时间函数、数学函数、字符函数、控制函数。让我...

  • 本系列文章由zhmxy555编写,转载请注明出处。 http://blog.csdn.net/zhmxy555/article/details/7335103作者:毛星云    邮箱: [email protected]    欢迎邮件交流编程心得以游戏文件来说,使用的位图数量相当多,因此都会先将位图存成文件,等到程序需要时再将...

  • 更多内容,欢迎关注微信公众号:全菜工程师小辉~前言在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理。这篇博客将针对第三个原因,进行更详细的讲解。首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并且这两个技术并不是等价的。零拷贝零拷贝是指避免在用户态(User-space)...

  • 一、预备知识—程序的内存分配  一个由c/C++编译的程序占用的内存分为以下几个部分  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器...

  • 我的爱机是一台ThinkPad T420,原装三星DDR 1333 4G内存一根,还剩一根内存位置,最近趁京东6.18促销,准备增加一根物理内存。为了确保兼容性,觉得仍然选购DDR 1333 4G内存,于是购买了金士顿这款,比如DDR3 1600的还贵。 这个安装过程完全参照该内存的网页提示进行 这里简单记录一下,以备...

  • 陪伴我多年的老本ThinkPad T420渐渐垂垂老矣, 我想更新一下可以更新的部分, 比如将2.5寸HDD更换为SSD, 将单条4G内存再增加一根, 凡此种种想法, 可能最后归结为如何获取该笔记本的硬件配置信息, 在windows下面使用鲁大师之类的检测软件, 也许很好搞定,但是在Ubuntu 14.04平台上如果办到呢? 很简单...

  • 一.内存错误出现的场景 这几天在重构ATS插件代码的过程中遇到了烦人的内存泄露问题, 周五周六连续两天通过走查代码的方法,未能看出明显的导致内存错误的代码, 同时也觉得C和C++混合编程得到一个动态库, 在一个.cpp主文件中,即用new又用malloc来动态分配内存, 可能会导致内存错误.后来网上调研和查资料发现, new和mal...