MFC案例:利用双缓冲技术绘制顶点可移动三角形

news/2025/2/26 5:45:58

        案例目标:在屏幕上出现一个三角形,同时显示各顶点坐标,当用鼠标选择某顶点并拖动时,三角形随鼠标移动而变形。具体步骤为:

一、在VS2022上建立一个基于对话框的MFC应用,项目名称:DrawMovableTriangle,其它步骤使用缺省。进入对话框界面,选择对话框,将其适当拉大一些。然后,删除其自带的控件。
二、打开解决方案资源管理器,找到DrawMovableTriangleDlg.h文件
  1、先以public方式声明一个函数:

  void drawTriangle(); //这是绘制三角形的主要函数

  2、再以protected方式声明三个变量:

 CPoint vertexPos[3]; //三角形的三个顶点坐标
 BOOL boolLBDown; //鼠标左键按下标志,TRUE按下,FALSE抬起
 int vertexNum; //顶点序号

三、利用类向导添加三个消息处理函数
  1、鼠标左键按下处理函数
       步骤:项目->类向导->确认类名是*Dlg->单击消息->找到并单击WM_LBUTTONDOWN->点击添加处理程序,这样在DrawMovabletriangleDlg.h文件中就有了如下声明:

  afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

  2、采用类似步骤,继续添加鼠标移动消息处理函数和左键抬起消息处理函数,如下:
      afx_msg void OnMouseMove(UINT nFlags, CPoint point);
      afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
      以上三个消息处理程序不但在这里进行了声明,同时还在DrawMovableTriangleDlg.cpp中进行了实现,只是实现函数中还没有我们需要的代码,我们需要做的就是将这些代码添上。
四、在DrawMovableTriangleDlg.cpp中找到OnInitDialog()函数,在TODO:行下面,完成几个变量的赋初值。代码如下:

  CRect rect;// 定义矩形类对象
  GetClientRect(rect);//GetClientRect将窗口客户区宽、高等数据存入rect
  vertexPos[0] = CPoint(rect.Width()/2,rect.Height()/4); //上顶点
  vertexPos[1] = CPoint(rect.Width()/4,rect.Height()*3/4); //左下顶点
  vertexPos[2] = CPoint(rect.Width()*3/4,rect.Height()*3/4); //右下顶点
  boolLBDown = FALSE; //默认鼠标左键未按下
  vertexNum = 0; //初始绘制三角形从上顶点开始

五、在DrawMovableTriangle.cpp文件中实现动态绘制三角形函数,在这个函数中要使用到双缓冲技术,具体代码如下:

void CDrawMovableTriangleDlg::drawTriangle()
{
	CRect rect; //声明矩形结构
	GetClientRect(&rect); //获取客户区数据存入rect
	CDC* pDC = GetDC();
	CDC memDC; //声明一个设备上下文对象(兼容对象)
	memDC.CreateCompatibleDC(pDC); //兼容对象与当前设备上下文pDC兼容(实际上兼容对象此时尚无空间)
	CBitmap NewBitmap, * pOldBitmap; //声明一个位图对象和一个位图指针
	NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); //位图对象与pDC兼容,这个位图可以代替pDC用于作图
	pOldBitmap = memDC.SelectObject(&NewBitmap);//位图对象选入兼容对象中,并将原位图信息存入位图指针,此时在memDC上作图实际上是在NewBitmap上作图
	memDC.FillSolidRect(rect, pDC->GetBkColor()); //用pDC的背景色填充memDC
	//在memDC上作图
	memDC.SelectStockObject(GRAY_BRUSH); //将灰色画刷选入兼容对象
	for (int i = 0; i < 3; i++) {
		CString str;
		str.Format((L"x = %d, y = %d"), vertexPos[i].x, vertexPos[i].y); 将三角形顶点坐标组合成字符串
		memDC.SetTextColor(RGB(255, 0, 0)); //设置兼容上下文对象的文字颜色
		memDC.TextOutW(vertexPos[i].x, vertexPos[i].y, str); //输出字符串到兼容上下文对象的文字颜色
		memDC.Rectangle(vertexPos[i].x - 5, vertexPos[i].y - 5, vertexPos[i].x + 5, vertexPos[i].y + 5); //给三角形顶点绘制小方块
		if (0 == i)  //画出三角形
			memDC.MoveTo(vertexPos[i]); //遇三角形第一个顶点则定位
		else
			memDC.LineTo(vertexPos[i]); //不是顶点时则连线(0-1,1-2)
	}
	memDC.LineTo(vertexPos[0]); //连接2-0
	pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY); //将兼容对象中的图像copy到设备上下文对象中
	memDC.SelectObject(pOldBitmap); //恢复兼容对象
	NewBitmap.DeleteObject();
	/* Windows 显示设备的属性,共有下面几种:位图、画刷、字体、画笔、区域。如果要设置它们到当前(或兼容)设备里,就需要使用SelectObject 函数,比如上面介绍的字体设置,就会用到这个函数。当你创建一个位图时,这时 Windows 就会在内存里分配一块内存空间,用来保存位图的数据。当你创建字体时,也会分配一块内存空间保存字体。如果程序只是分配,而不去删除,就会造成内存使用越来越多,最后导到 Windows 这幢大楼倒下来。如果你忘记删除它,就造成了内存泄漏。因此,当你创建显示设备资源时,一定要记得删除它们啊,否则运行你的程序越长,就导致系统不稳定。记得使用DeleteObject 函数去删除它们,把占用的内存释放回去给系统。*/
	memDC.DeleteDC();
	/* 如果一个设备上下文环境的句柄是通过调用GetDC函数得到的,那么应用程序不能删除该设备上下文环境,应该调用ReleaseDC函数来释放该设备上下文环境。如果是自己生成的,则用DeleteDC释放所占用的资源 */
}

六、接着,还是在DrawMovableTriangle.cpp中找到那三个消息处理函数中,为其添加相关代码如下:
  1、在void CDrawMovableTriangleDlg::OnLButtonDown(UINT nFlags, CPoint point)中TODO:行下面,添加一句代码:

boolLBDown = TRUE;

  2、在176 void CDrawMovableTriangleDlg::OnMouseMove(UINT nFlags, CPoint point)中TODO:行下面添加:

	CDC* pDC = GetDC();
	for (int i = 0; i < 3; i++) {
		if (point.x<vertexPos[i].x + 5 && point.x>vertexPos[i].x - 5 && point.y<vertexPos[i].y + 5 && point.y>
			vertexPos[i].y - 5) {  //判断鼠标是否在三角形顶点上下或左右5个像素范围内
			SetCursor(LoadCursor(NULL, IDC_HAND));
			/*上面的设置光标样式为手型,LoadCursor加载windows 自带的光标资源时第一个参数必须为空*/
			vertexNum = i;
		} //标记被点击的三角形顶点序号
	}
	if (boolLBDown)  vertexPos[vertexNum] = point;//将鼠标位置付给顶点,这里鼠标状态是即按下又在移动
	ReleaseDC(pDC);//释放pDC,从用此函数也证明pDC不是memDC,若是memDC须用memDC.DeleteDC();
	drawTriangle(); //调用动态画三角形程序

  3、在207 void CDrawMovableTriangleDlg::OnLButtonUp(UINT nFlags, CPoint point)中TODO:行下面添加:

boolLBDown = FALSE; //恢复左键弹起设置,否则选上三角形定点后放不开

五、运行效果截图:


http://www.niftyadmin.cn/n/5868090.html

相关文章

IDEA-插件开发踩坑记录-第五坑-没有飞机场导致无法访问GITHUB导致的讨厌问题

背景 在JetBrains-intellij-idea 插件开发时&#xff0c;出现一个不影响运行&#xff0c;但影响心情的错误提示&#xff1a; Cannot resolve the latest Gradle IntelliJ Plugin version org.gradle.api.GradleException: Cannot resolve the latest Gradle IntelliJ Plugin v…

《OpenCV》——实例:答题卡识别

答题卡识别 实例内容&#xff1a; 该实例实现了一个基于计算机视觉技术的答题卡自动识别与评分系统&#xff0c;利用 OpenCV 库对答题卡图像进行处理和分析&#xff0c;最终得出答题卡的得分。 实例步骤&#xff1a; 导入必要的库 import numpy as np import cv2导入num…

hot100_108. 将有序数组转换为二叉搜索树

hot100_108. 将有序数组转换为二叉搜索树 思路 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#…

基于 spring boot+vue 的仓储管理系统 的设计与实现

下载链接 1 引言 随着全球化的加速和国际互联网技术的飞速发展&#xff0c;越来越多的企业开始构 建自己的电子商务平台。在这个信息化时代&#xff0c;基于网络的信息服务和商务服务 已经成为现代企业运营的核心组成部分。不再满足于仅有发布信息功能的静态 网站&#xff0…

TDengine 产品组件:taosExplorer

taosExplorer 是一个为用户提供 TDengine 实例的可视化数据库管理交互工具的 web 服务&#xff0c;使用浏览器打开。虽然它没有开源&#xff0c;但随开源版安装包免费提供。 本节主要讲述其安装和部署。它的各项功能都是基于简单易上手的图形界面&#xff0c;可以直接尝试&…

vscode多文件编译构建(CMake)和调试C++

目录 1. CMake 基础构建工具及作用相关配置文件 2. 配置 tasks.json关键字段详细解释 3. 配置 launch.json关键字段详细解释 4. 配置 CMakeLists.txt关键部分详细解释 5. 构建和调试项目1. 仅构建项目1.1 任务执行顺序1.2 cmake 任务执行详情1.3 build 任务执行详情1.4 构建后的…

tensorflow + sionna 安装踩坑记录(待补充)

1.本人基础配置 cpu笔记本一台&#xff0c;使用mobaxterm远程控制gpu服务器&#xff0c; 没有sudo权限。 2.Tensorflow安装 请打开官方英文版安装介绍 https://tensorflow.google.cn/install/pip&#xff0c;中文版可能会缺失部分提示信息。 conda create -n tf_sionna pyt…

《白帽子讲Web安全》学习:深入解析Cookie与会话安全

目录 导言 一、Cookie 的原理与作用 二、Cookie 面临的安全风险 三、Cookie的核心安全属性 1.Domain 属性 2.Path 属性 3.Expires 属性 4.HttpOnly 属性 5.Secure 属性 6.SameSite 属性 7.SameParty 属性 四、安全使用Cookie 1.正确设置Cookie属性值 2.Cookie前缀…