【MFC】绘制自定义控件-显示图片(支持放大操作)

目录

  • 一、CDC类(二级缓存)
  • 二、计算视口
  • 三、放大操作
  • 代码中初始化操作(方便以后cv)

一、CDC类(二级缓存)

CDC类是设备上下文的核心类,它的作用是抽象化对图形输出设备(像屏幕、打印机、内存位图等)的访问,借助CDC我们可以在屏幕上绘制图像。

自定义控件中采用了双缓冲技术,防止在绘制图像时屏幕闪烁。其中用到了关键的几个类和函数,如下。

//成员变量
CDC m_ImageDC;								//	源图片DC
HBITMAP m_hImageBitmap;						//	位图
BITMAPINFO* m_pBitmapInfo;
void* m_pBuffdata;							//	图像数据CDC m_buffDC_image;							// 二级缓存
CBitmap m_cBitmap;

图像放在控件上,图像的大小和控件的大小可能不一样,这时需要将图像进行压缩或放绘制到控件上(需要直接操作数据,调用Windows API),故在第一个CDC中使用了HBITMAP位图。创建位图调用Windows API接口函数 CreateDIBSection()函数。该函数直接绑定数据指针m_pBuffdata
,可以直接操作数据。

计算好压缩因子、视口、窗口显示区域,通过StretchBlt()函数进行压缩到m_ImageDC中,再通过BitBlt()函数将m_ImageDC复制到m_buffDC_image,再将m_buffDC_image复制到屏幕上。

进行放大操作就是调节视口区域,再计算压缩因子进而计算窗口显示区域,再把图像放到指定区域。

二、计算视口

//成员变量
CSize m_tSizeWnd;							//	控件显示窗口的尺寸
CSize m_tSizeImg;							//	图片的尺寸
int m_iImageSize;							//	图片的字节数CRect m_reShowImage;						//	显示图像区域(视口)
CRect m_reShowWnd;							//	显示窗口区域double m_dChangeNum;						//	压缩因子(变化因子)

要求:将图像显示在控件上,并且保证在控件上居中。

计算缩放因子

图像不一定是完美契合控件大小,要等比例缩放需计算缩放因子。
计算窗口的宽高和图像宽高的比例,为了图像全部显示在控件上,我们选择最小的比例当缩放因子。

//计算缩放因子
double dChangeX = (double)m_tSizeWnd.cx / m_tSizeImg.cx;
double dChangeY = (double)m_tSizeWnd.cy / m_tSizeImg.cy;m_dChangeNum = min(dChangeX, dChangeY);

计算视口(图像全部显示在空间上的视口大小)

图像的显示区域就是视口,图像完全显示到控件上,及视口就是整个图像的区域。

//视口大小(相对于图像的坐标)
m_reShowImage.left = 0;
m_reShowImage.top = 0;
m_reShowImage.right = m_reShowImage.left + m_tSizeImg.cx;
m_reShowImage.bottom = m_reShowImage.top + m_tSizeImg.cy;

计算控件显示图像的区域(居中)

第一步:通过压缩因子计算压缩后图像的宽高
第二步:通过控件的宽高-压缩后图像的宽高再除以2,得到居中后的坐标

double dWid = static_cast<double>(m_reShowImage.right - m_reShowImage.left) * m_dChangeNum;
double dHit = static_cast<double>(m_reShowImage.bottom - m_reShowImage.top) * m_dChangeNum;int iWid = static_cast<int>(dWid + 0.5);  // 四舍五入
int iHit = static_cast<int>(dHit + 0.5);m_reShowWnd.left = (m_tSizeWnd.cx - iWid) >> 1;
m_reShowWnd.top = (m_tSizeWnd.cy - iHit) >> 1;
m_reShowWnd.right = m_reShowWnd.left + iWid;
m_reShowWnd.bottom = m_reShowWnd.top + iHit;

再调用第一节说的StretchBlt()函数将图像缩放复制到二级缓存中

::StretchBlt(m_buffDC_image.GetSafeHdc(), m_reShowWnd.left,m_reShowWnd.top,m_reShowWnd.Width(),m_reShowWnd.Height(),m_ImageDC.GetSafeHdc(),m_reShowImage.left,m_reShowImage.top,m_reShowImage.Width(), m_reShowImage.Height(),SRCCOPY);

三、放大操作

放大操作:计算新视口

当鼠标点击图像时,图像放大。鼠标指向的区域是相对图像坐标是不变的,通过这个坐标计算新的视口。

补充:当图像需要放大两倍时,就是视口区域缩小两倍,再显示控件上就是放大两倍的效果。

在这里插入图片描述
重写鼠标点击事件,我们可以得到鼠标点击的坐标(x,y)。因为是等比例缩放,通过缩放因子计算可以得到W2和H2。及可以算出坐标到新视口边的距离。

再计算之前需要将坐标转换为图像坐标系上的坐标。(图上画的两个矩形都是图像)

坐标转换(控件上的坐标转换成图像上的坐标)

//将窗口的坐标转化为图像上的坐标
//因为图像是通过缩放因子等比例缩放显示在控件上的,故可以通过这层关系
//计算相对于图像上的坐标
void MyImageView::OnLButtonDblClk(UINT nFlags, CPoint point)
{point.x /= m_dChangeNum;point.y /= m_dChangeNum;

计算新的缩放因子、计算新的视口大小

double dOldChangeNum = m_dChangeNum;
double newScale = 2 * m_dChangeNum;
newScale = max(m_dMinScale, min(m_dMaxScale, newScale));
double scaleRatio = dOldChangeNum / newScale;  //	1/2//通过新的缩放因子得出新视口的宽高
int iWid = m_reShowImage.Width() * scaleRatio;
int iHit = m_reShowImage.Height() * scaleRatio;//通过比例关系 计算出视口的区域坐标
m_reShowImage.left = point.x - (point.x * iWid / m_tSizeImg.cx);
m_reShowImage.top = point.y - (point.y * iHit / m_tSizeImg.cy);
m_reShowImage.right = m_reShowImage.left + iWid;
m_reShowImage.bottom = m_reShowImage.top + iHit;

至此计算出新视口的区域,再进行计算新显示窗口区域就可以完成放大操作。

代码中初始化操作(方便以后cv)

	CDC* pDC = pWnd->GetDC();m_pBitmapInfo = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 255);if (NULL != m_pBitmapInfo){for (int i = 0; i < 256; i++){m_pBitmapInfo->bmiColors[i].rgbRed = i;m_pBitmapInfo->bmiColors[i].rgbGreen = i;m_pBitmapInfo->bmiColors[i].rgbBlue = i;}m_pBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);m_pBitmapInfo->bmiHeader.biBitCount = (model == false) ? 8 : 24;m_pBitmapInfo->bmiHeader.biPlanes = 1;m_pBitmapInfo->bmiHeader.biCompression = 0;m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 0;m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 0;m_pBitmapInfo->bmiHeader.biClrImportant = 0;m_pBitmapInfo->bmiHeader.biClrUsed = 0;m_pBitmapInfo->bmiHeader.biHeight = tSizeImg.cy;m_pBitmapInfo->bmiHeader.biWidth = tSizeImg.cx;int bitCount = (model == false) ? 8 : 24;m_iImageWidthStep = ((tSizeImg.cx * bitCount / 8) + 3) & ~3;m_pBitmapInfo->bmiHeader.biSizeImage = m_iImageWidthStep * tSizeImg.cy;m_ImageDC.CreateCompatibleDC(pDC);m_ImageDC.SetStretchBltMode(HALFTONE); //( COLORONCOLOR ); //(HALFTONE);m_ImageDC.SetBkMode(TRANSPARENT);if (m_hImageBitmap){DeleteObject(m_hImageBitmap);m_hImageBitmap = NULL;}m_hImageBitmap = CreateDIBSection(m_ImageDC.m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, &m_pBuffdata, NULL, 0);m_iImageSize = m_iImageWidthStep * tSizeImg.cy * sizeof(unsigned char);memset(m_pBuffdata, 0, m_iImageSize);m_ImageDC.SelectObject(m_hImageBitmap);}//二级缓存初始化m_cBitmap.CreateCompatibleBitmap(pDC, m_tSizeWnd.cx, m_tSizeWnd.cy);m_buffDC_image.CreateCompatibleDC(pDC);m_buffDC_image.SetStretchBltMode(HALFTONE); //( COLORONCOLOR ); //(HALFTONE);m_buffDC_image.SetBkMode(TRANSPARENT);m_buffDC_image.SelectObject(&m_cBitmap);

注:需要重写这两个函数

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);//这个函数中 设置格式SS_OWNERDRAW 之后 ,调用Invalidate(false)
//才会去执行DrawItem()函数
virtual void PreSubclassWindow()
{ModifyStyle(SS_TYPEMASK,SS_OWNERDRAW | SS_NOTIFY, SWP_FRAMECHANGED);CStatic::PreSubclassWindow();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/85580.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/85580.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Proteus新工程中放置基本元器件

视频教程&#xff1a; [最详细]Proteus新建第一个工程与快捷键设置 操作步骤 1选择这个黄色的三角&#xff0c;然后点击旁边的P,开始找元件。 2点开P后&#xff0c;呈现如下图界面&#xff0c;我们在Keyword栏中&#xff0c;输入stm32&#xff0c;然后他会自动出现对应的元件&…

PRUD币推动健康数据资产化,开启Web3隐私金融新时代

在全球健康科技与数据主权浪潮下&#xff0c;PRUD币&#xff08;Prudential Utility & Data Token&#xff09;正成为Web3健康金融领域中的重要通证。项目通过链上身份绑定、健康行为证明、隐私计算与NFT机制&#xff0c;为用户打造了“健康数据资产化”的创新路径&#xf…

Mac 安装 finalshell

1.下载 地址&#xff1a;FinalShell官网 第一个进入选择对应的 mac 版本下载。 下一步下一步完成安装。 2.链接虚拟机&#xff0c;点击图示文件夹 点击新建链接&#xff0c;新建 SSH 链接 3.去 vmware 中查询 Linux 系统的 IP,使用 ip addr 命令或者 ifconfig 命令皆可。 ip…

Javaweb - 2 HTML

目录 HTML 入门 1. HTML & CSS & JavaScript 的作用 2. 什么是 HTML 3. 什么是超文本 4. 什么是标记语言 5. HTML 基本结构 6. HTML 概念词汇解释 7. HTML 的一些语法规则 8. 开发工具 VsCode 安装插件&#xff1a; 常见设置&#xff1a; HTML 常见标签 …

CWGAN-GP 增强型 CAE 在非 IID 数据集中用于 5G-NR 干扰检测

抽象 在不断扩大的 5G-NR 无线蜂窝网络领域中&#xff0c;无线干扰攻击作为安全攻击普遍存在&#xff0c;损害了接收信号的质量。我们通过将加性高斯白噪声 &#xff08;AWGN&#xff09; 合并到真实世界的同相和正交 &#xff08;I/Q&#xff09; OFDM 数据集中来模拟干扰环境…

JavaEE-Spring-Web-Mvc

Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为"Spring MVC". Servlet 是⼀种实现动态⻚⾯的技术. 准确来讲Serv…

Linux从入门到入门

系统教程学习类 Ubuntu 从入门到精通 系统页面/基本操作类 Ubuntu20.04终端固定终端到左边的导航栏_ubuntu20.04设置菜单固定-CSDN博客Ubuntu 20.04 系统5分钟后老是自动锁屏_修改锁屏时间-CSDN博客 命令类 拷贝&#xff1a;将 下载 文件夹里的.sh文件 复制到opt目录下 sudo cp…

AI自动生成Git提交信息-git AI Commit

在现代软件开发中&#xff0c;编写清晰且一致的Git提交信息对于维护项目历史和促进团队协作至关重要。然而&#xff0c;为每次变更手动撰写描述性提交信息可能耗时&#xff0c;尤其是处理复杂差异或大型项目时。AI Commit 是一个利用AI分析Git差异并生成符合Conventional Commi…

【三大前端语言之一】样式:CSS详解

【三大前端语言之一】样式&#xff1a;CSS详解 在了解完HTML的有关知识后&#xff0c;我们应该知道&#xff0c;一个网页光有框架还不行&#xff0c;必须还得有装饰它的样式。就好比房子的结构搭好了&#xff0c;但如果没有油漆、没有窗帘、没有家具&#xff0c;就无法真正展现…

Spring AI 聊天记忆功能实战(一):从接口设计到生产实践

Spring AI 聊天记忆功能实战&#xff08;一&#xff09;&#xff1a;从接口设计到生产实践 在构建AI对话应用时&#xff0c;聊天记忆管理及存储是实现连贯上下文交互的关键组件。而大模型&#xff08;LLM&#xff09;本质上是无状态的&#xff0c;这意味着它们不会保留历史交互…

Element Plus 对话框 el-dialog 和 抽屉 el-drawer 的使用注意项(使用 div 包裹)

总结&#xff1a;使用 div 包裹&#xff01;&#xff01;&#xff01; 详细说明&#xff1a; 对话框 el-dialog 或 抽屉 el-drawer 样式的设置说明&#xff1a; 要想有效设置 el-dialog 或 el-drawer 的样式&#xff0c;需确保 el-dialog 或 el-drawer 的上层不是template&am…

【python】简单演示 gateway、service、client的工作原理

gateway 看起来主要是做协议转换的A gateway is a network node that acts as an entrance and exit point, connecting two networks that use different protocols. It allows data to flow between these networks, essentially acting as a translator between different c…

数据仓库面试题合集⑥

实时指标体系设计 + Flink 优化实战:面试高频问题 + 项目答题模板 面试中不仅会问“你做过实时处理吗?”,更会追问:“实时指标体系是怎么搭建的?”、“你们的 Flink 稳定性怎么保证?” 本篇聚焦实时指标体系设计与 Flink 优化场景,帮你答出架构设计力,也答出调优实战感…

Vue + AbortController 请求取消弹窗 hook 封装

背景 实际业务开发场景中&#xff0c;往往存在有些大数据请求的需求&#xff0c;一旦请求发起加载遮罩后用户就无法操作了&#xff0c;直接尬住&#xff0c;所以提供一个支持取消查询的功能还是很有必要的&#xff0c;为了在全业务接口都能使用封装一个hook。 ✋为什么要用 A…

数据结构相关

1 问题 如何辨析数据对象和数据结构&#xff1f;如何设计多种储存结构以及他们特性有什么&#xff1f;内存条和硬盘的区别&#xff1f; 2 方法 明晰俩者的定义数据对象是性质相同的有限个数据元素的集合&#xff0c;他是数据的一个子集。数据结构是指所涉及的数据元素的集合以及…

MacOS内存管理-删除冗余系统数据System Data

文章目录 一、问题复现二、解决思路三、解决流程四、附录 一、问题复现 以题主的的 Mac 为例&#xff0c;我们可以看到System Data所占数据高达77.08GB&#xff0c;远远超出系统所占内存 二、解决思路 占据大量空间的是分散在系统中各个位置Cache数据&#xff1b; 其中容量最…

纯视觉SOTA!华科小米推出ReCogDrive:结合VLM和强化学习的端到端自动驾驶框架

摘要 端到端自动驾驶的研究目前越来越火热&#xff0c;现有方法通过视觉语言模型&#xff08;VLM&#xff09;来解决其在长尾场景中性能降低的问题&#xff0c;但是仍然存在一些局限性。本文提出了ReCogDrive&#xff0c;它将VLM与基于扩散的轨迹规划器相结合&#xff0c;并且采…

MySQL慢SQL优化全攻略:从诊断到调优

目录 慢SQL日志分析与诊断 开启慢查询日志 慢查询日志分析工具 慢SQL优化策略 1. 避免SELECT * 查询 2. 创建高效索引 索引选择原则 索引使用注意事项 3. 使用EXPLAIN分析执行计划 4. 优化排序操作 5. 解决深分页问题 6. 避免全表扫描 7. 优化JOIN操作 8. 合理使用…

OPENPPP2 VMUX 技术探秘(高级指南)

&#x1f680; VMUX技术分析&#xff1a;OPENPPP2中的虚拟多路复用技术 &#x1f31f; 一、技术目标 &#x1f517; 连接多路复用 通过单个或多个物理链路&#xff0c;承载多个逻辑TCP连接。 &#x1f680; 高性能传输 支持数据包乱序重组实现动态流量控制&#xff08;拥塞检测…

Linux系统时间不对导致mysql初始化失败:Data Dictionary initialization failed.(数据字典版本验证失败)

文章目录 问题描述分析**问题原因分析****解决方案****1. 修正系统时间****2. 检查数据目录完整性****3. 重新初始化数据目录****4. 调整 MySQL 配置** **验证与后续步骤****注意事项** 其他说明 问题描述 mysql数据初始化失败&#xff0c;发现系统时间是1970年&#xff0c;我…