当前位置: 首页 > news >正文

MFC案例:使用键盘按键放大、缩小窗口图像的实验

       当在对话框窗口居中显示一幅图像时,图像的尺寸可能大于或小于窗口的尺寸,这时我们希望通过使用按键“+”进行图像放大显示,使用按键“-”进行缩小显示(当然也可以使用其它按键)。下面开始使用MFC进行这个实验,编译环境是VS2022。
       思路:首先,把一幅图像按原尺寸(不做拉伸)居中显示到窗口中,使我们能看到图像原始的样子;然后,进行程序核心部分,使用键盘消息处理函数接收键盘消息,当接收到“+”或“-”按键按下消息时,相应的显示图像的某一区域。原理上,在窗口尺寸既定的情况下,图像选定区域越小则显示出来越大,反之亦然。
       实验的具体步骤如下:
一、建立一个基于对话框的MFC项目
       打开VS2022->创建新项目->MFC应用->下一步->项目名称填写:picEnlgReduTest->创建->应用程序类型选择:基于对话框->完成(其余项目均按缺省)。
二、在桌面上放一张jpg图片,我这里的路径是:C:\Users\Administrator\Desktop\2222.jpg。(内容是我自己拍摄的月季花)
三、把图像文件读入内存并获得这幅图像的尺寸以及窗口尺寸等基本数据,这项工作我们放到对话框的初始化程序中进行。具体是找到picEnlgReduTestDlg.cpp中的OnInitDialog()函数,在TODO:行下面添加下列代码:

	img.Load(L"C:\\Users\\Administrator\\Desktop\\1111.jpg"); //载入图像文件imgWidth = img.GetWidth();// 返回图像的宽度(以像素为单位)imgHeight = img.GetHeight();// 返回图像的高度CRect DCrect; //定义矩形对象(用于接收对话框客户区数据)GetClientRect(DCrect); //获得窗口客户区坐标、宽高等数据DCwidth = DCrect.Width();//客户区宽度DCheight = DCrect.Height();//客户区高度

       在上面的代码中使用的img、imgWidth、imgHeight、DCwidth、DCheight几个变量,在对话框类的其它函数中可能还会用到,因此这几个变量要放在picEnlgReduTestDlg.h中定义,定义方式是public:,具体如下:

    CImage img; //声明用于载入图像文件的CImage对象int imgWidth, imgHeight; //载入到img中的图像的宽、高(像素)int DCwidth, DCheight;//窗口客户区宽、高(像素)

四、在鼠标移动消息处理程序中把图像按照原始大小显示到窗口
        这一步骤在OnInitDialog()函数中是不能进行的,因为此时对话框还没有完成初始化。现在我们把这一工作放到鼠标移动消息处理函数中进行,因为程序开始运行窗口出现后,只要鼠标出现在窗口范围内,第一时间就可以将图像显示到对话框中。但存在一个问题,后边随着鼠标的经常性移动,会反复将原始大小图像显示到对话框窗口,如此会影响到后续的操作。为此,设置一个逻辑变量isFirst,让这个显示过程仅执行一次。这个isFirst也放到picEnlgReduTestDlg.h中去定义,代码就一句:

BOOL isFirst=1; // 等于1时显示图像,显示后立即置为0

       下面,我们进入类向导,类名选择CpicEnlgReduTestDlg,其余按缺省,然后点开消息,找到WM_MOUSEMOVE,点击“添加处理程序”。这时在picEnlgReduTestDlg.cpp中可以看到OnMouseMove()函数,在这个函数的TODO:行下添加下列代码:

   if (isFirst == 1) {CDC* pDC; //声明设备上下文指针pDC = GetDC(); //获得当前设备上下文指针(屏幕)img.Draw(pDC->m_hDC, //设备上下文对象(pDC->m_hDC通过指针获得对象)(DCwidth - imgWidth) / 2, (DCheight - imgHeight) / 2 //图像左上角在窗口中的坐标,上面计算的坐标可以保证图像中心与窗口中心重合);pDC->DeleteDC(); //清理设备上下文指针isFirst = 0; //将其置为0,使上面的显示代码仅执行一次}

       说明:上面的这段代码,功能是将图像居中显示到窗口上,程序运行时只要鼠标在窗口范围内,这个程序即会运行起来。这段代码的核心语句是调用CImage::Draw()函数。这里Draw函数仅使用了前三个参数,忽略后边参数意义是表示图像是以原始大小(分辨率)显示在窗口上的,当图像尺寸大于窗口尺寸时,部分图像内容会显示不出来,但分辨率是原来的。这个函数是本程序使用的主要函数,后边还会继续使用,函数中参数含义如下:
       参1:CDC类对象,也就是图像显示目标
       参2、参3:图像左上角显示在窗口上的坐标。这个坐标允许选择在窗口外面,不报错。
五、在键盘按下消息处理程序中实现显示图像的缩放
       还是通过类向导,类名仍选择CpicEnlgreduTestDlg,其余按缺省,然后点击消息,找到WM_KEYDOWN,点击“添加处理程序”,这时在picEnlgReduTestDlg.cpp中会增加一个函数OnKeyDown()。这个函数处理按键被按下去了的消息,当然具体到是哪个按键被按下,还需要我们根据这个函数返回的参数值判断。OnKeyDown函数带着三个参数,头一个参数nChar是被按下键的键值,通过这个键值可以确定是哪个键被按下。在OnKeyDown函数的TODO:行下面,添加下列代码:

  if (nChar == 107 || nChar==109) { //当+、-号被按下时int imgShowX = (imgWidth / 2 - DCwidth / 2) + 10 * countPlus - 10 * countMinus;int imgShowY = (imgHeight / 2 - DCheight / 2) + 10 * countPlus - 10 * countMinus;//imgShowX、imgShowY图像拟显示区域左上角坐标;实际选取的图像区域小于窗口尺寸是放大显示,反之是缩小显示//选取的图像区域增大是缩小显示。int imgShowWidth = DCwidth - 20 * countPlus + 20 * countMinus;int imgShowHeight = DCheight - 20 * countPlus + 20 * countMinus;//imgShowWidth、imgShowHeight图像中拟显示区域的宽高(原理同上)if (nChar == 107 && imgShowWidth > 20 && imgShowHeight>20)	countPlus++;//+号累计按下次数记录,当图像选取区域宽高小于20个像素时,按+号功能失效if (nChar == 109 && imgShowWidth < 5*DCwidth )countMinus++;//当图像选取区域宽度达到窗口宽度的5倍时,按-号功能失效CDC* pDC; //声明设备上下文指针pDC = GetDC(); //获得当前设备上下文指针(指屏幕)SetStretchBltMode(pDC->m_hDC, COLORONCOLOR); //图像拉伸变形时会出现失真,做此设置则不会失真if (nChar == 109 && (imgShowX < 0 || imgShowY < 0)) pDC->FillSolidRect(0, 0, DCwidth, DCheight, RGB(255, 255, 255)); //当缩小显示且显示内容填不满整个窗口时,重绘窗口背景img.Draw(pDC->m_hDC, //设备上下文0,0,//窗口左上角坐标DCwidth,DCheight,//窗口宽、高(像素)imgShowX,imgShowY, //图像拟显示区域做上角坐标imgShowWidth,imgShowHeight//图像拟显示区域的宽、高);pDC->DeleteDC(); //清理设备上下文指针

       说明:上面这段代码的功能是在接收到键盘按下“+”或“-”键消息时,对图像放大或缩小显示,同时保证图像的中心点不变,始终与窗口的中心重合。当图像放大到超过窗口的尺寸时,超出部分不被显示;当图像缩小到小于窗口的尺寸时,空出的区域需要用白色填充。放大、缩小都设置了停止点,以防程序崩溃,具体见代码。核心函数仍是CImage::Draw()(当然是重载的),这里使用的参数要多一些,共有9个:
       参1:CDC对象
       参2参3:窗口显示区域的左上角坐标
       参4参5:窗口显示区域的宽、高
       参6参7:图像中拟显示区域的左上角坐标
       参8参9:图像中拟显示区域的宽高
       注意,上面涉及两个坐标,一个是窗口的,一个是图像的不要混淆。
六、到此,实验相关的代码部分已经写好,运行后效果尚可;存在一点小问题:即缩小显示进行到小于窗口需重绘背景时,有些闪烁,如要解决可使用缓冲技术,这里不展开。
   运行效果截图:
   鼠标移动消息效果图:


   放大效果图:


 

 缩小效果图:

相关文章:

  • 21.disql命令登录达梦数据库,查询并操作数据库
  • label studio的安装
  • 网络安全风险评估报告书模版(Word)
  • python三维矩阵的维度
  • Minio Linux 安装 systemctl启动配置
  • 4月23日作业
  • AI 入门开发之 LangChain.js 与 LCEL
  • 重塑智慧出行新生态,德赛西威全新战略愿景发布
  • 西门子S7-200SMART 控制Profinet闭环步进MD-4250-PN (1)
  • 0基础可以考MySQL OCP么?备考时间需要多久?
  • 父组件弹窗调用子组件时,无法通过ref、provide、inject等方法调用子组件的方法
  • Dhtmlx Gantt教程
  • kubernetes》》k8s》》证书有效期
  • 2.第二章:政策法规与标准体系
  • c++中的enum变量 和 constexpr说明符
  • 【项目篇】仿照RabbitMQ模拟实现消息队列
  • 咖啡机语音芯片方案-WTN6040FP-14S直接驱动4欧/3W喇叭-大功率输出
  • 彻底禁用windows的语音识别快捷键win+ctrl+s
  • date-picker组件的shortcuts为什么不能配置在vue的data的return中
  • 量子混合计算革命:Qiskit 3.0开启云上量子开发新时代
  • 人民日报开新栏,冼星海之女追忆父亲创作《黄河大合唱》
  • 主动权益基金一季度重仓股出炉:腾讯跃升至第一,阿里、比亚迪、中芯国际新进前十
  • 从“龙队”到“龙副”,国乒这批退役球员为何不爱当教练了
  • 乌克兰关切有中国公司帮助俄罗斯制造军事硬件,外交部:坚决反对无端指责
  • 浙江严禁中小学节假日集体补课,省市县教育部门公布举报电话
  • 宝马董事长:继续倡导自由贸易和开放市场,坚信全球性挑战需要多协作而非对立,将引入DeepSeek