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

devtools/2025/2/28 10:05:03/

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

一、在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将窗口客户区宽、高等数据存入rectvertexPos[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); //获取客户区数据存入rectCDC* 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]); //遇三角形第一个顶点则定位elsememDC.LineTo(vertexPos[i]); //不是顶点时则连线(0-1,1-2)}memDC.LineTo(vertexPos[0]); //连接2-0pDC->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.ppmy.cn/devtools/163321.html

相关文章

C++大整数类的设计与实现

1. 简介 我们知道现代的计算机大多数都是64位的&#xff0c;因此能处理最大整数为 2 64 − 1 2^{64}-1 264−1。那如果是超过了这个数怎么办呢&#xff0c;那就需要我们自己手动模拟数的加减乘除了。 2. 思路 我们可以用一个数组来存储大数&#xff0c;数组中的每一个位置表…

流式抽样唯一元素方案设计

在高流量、源源不断的请求接口中&#xff0c;一个用户可能会发送多个请求&#xff0c;因此如何在这种情况下抽样并记录不重复用户的信息是一个重要的设计问题。本设计考虑多种方案&#xff0c;旨在通过有效的抽样策略来减少存储负担&#xff0c;同时确保数据的代表性。 确定性…

使用 Kettle (PDI) 连接 SQL Server 数据库

使用 Kettle (PDI) 连接 SQL Server 数据库 以下是配置步骤: 1. 下载 JDBC 驱动 Microsoft 官方驱动:下载地址 解压后获取 mssql-jdbc-<version>.jar 文件(或 jtds-x.x.x.jar 若使用 JTDS) 网络不好下面网址下载 mssql:mssql驱动下载jtds:jtds驱动下载Microsoft…

【Python爬虫(96)】从0到1:打造爬虫驱动的数据分析平台

【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发…

挖src实用脚本开发(二)

文章目录 技术原理代码实现一代码实现二总结 这篇文章记录cms识别脚本。 技术原理 1.使用在线平台识别&#xff0c;比如whatcms&#xff0c;fofa等 2.自己写脚本识别&#xff0c;但是指纹库麻烦&#xff0c;需要耗费大量精力 代码实现一 这里我使用的是whatcms接口&#xff0…

51单片机-按键

1、独立按键 1.1、按键介绍 轻触开关是一种电子开关&#xff0c;使用时&#xff0c;轻轻按开关按钮就可使开关接通&#xff0c;当松开手时&#xff0c;开关断开。 1.2、独立按键原理 按键在闭合和断开时&#xff0c;触点会存在抖动现象。P2\P3\P1都是准双向IO口&#xff0c;…

蓝桥杯备考:贪心算法之矩阵消除游戏

这道题是牛客上的一道题&#xff0c;它呢和我们之前的排座位游戏非常之相似&#xff0c;但是&#xff0c;排座位问题选择行和列是不会改变元素的值的&#xff0c;这道题呢每每选一行都会把这行或者这列清零&#xff0c;所以我们的策略就是先用二进制把选择所有行的情况全部枚举…

Spring Boot项目@Cacheable注解的使用

Cacheable 是 Spring 框架中用于缓存的注解之一&#xff0c;它可以帮助你轻松地将方法的结果缓存起来&#xff0c;从而提高应用的性能。下面详细介绍如何使用 Cacheable 注解以及相关的配置和注意事项。 1. 基本用法 1.1 添加依赖 首先&#xff0c;确保你的项目中包含了 Spr…