跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

计算机图形学 Visual C++ MFC 基础绘图开发

综述由AI生成基于 Visual C++ MFC 框架的计算机图形学基础开发实践。通过创建单文档 MFC 项目,利用 CDC 类提供的 MoveTo、LineTo、Rectangle 等函数绘制点、线、面等基本图形元素,模拟行政中心、道路、河流及建筑布局。此外,还演示了使用 Polygon 函数绘制叶片投影并实现居中显示的方法。文章涵盖了从项目搭建到具体绘图逻辑的实现过程,为二维图形在屏幕坐标中的映射及三维建模基础提供了示例。

路由之心发布于 2026/3/29更新于 2026/5/3028 浏览
计算机图形学 Visual C++ MFC 基础绘图开发

实验目的和要求

搭建能够显示图形、文字的单文档绘图环境。

(1)在 OnDraw 函数内,使用 MFC 封装函数(MoveTo, LineTo, Rectangle, Ellipse 等)和点、线、矩形、椭圆/圆等基本图形,表示出指定实验区域的行政中心(或实验样点、河流(或类型边界)和行政区(或实验区)等图形。

(2)使用阔叶树种的叶片采集数据,表示出叶片的投影图形,为三维建模奠定基础。

提示:可通过平移坐标点,使数据显示在客户区的中央。

基本原理

(1)MFC(Microsoft Foundation Classes)库是 Microsoft 为利用 VC++ 开发 Windows 应用程序而提供的应用程序框架。在这个框架的支持下,对于不同的应用程序,编程的主要任务是填写各自特殊部分的代码。MFC 类库由 130 多个类组成,封装了两千多个 API 函数。

(2)MFC 程序的设计流程,如图 1:

图 1 程序的开发流程

开发环境

Visual C++ 6.0

实验步骤与结果

4.1 创建 MFC 项目

(1)启动 Visual C++ 6.0。

(2)从 File 菜单中选择 New 选项,出现 New 对话框。选中 Projects 分页,在 Projects 面板中左侧的项目类型列表框中单击选中 MFC AppWizard[exe] 项,创建一个 MFC 应用程序。

(3)单击 OK 按钮。出现 MFC AppWizard-Step 1 对话框。创建基于 Single document(单文档)。

(4)其他设置默认,完成创建。

(5)编译执行,查看效果。

4.2 绘制点

(1)增加成员函数 DrawPoints。

(2)编辑 DrawPoints 函数。代码如下:

void CExp_01View::DrawPoints(CDC *pDC) { //绘制邻近的点集,以突出显示
    pDC->SetPixel(100,100,RGB(255,0,0));
    pDC->SetPixel(101,100,RGB(255,0,0));
    pDC->SetPixel(100,101,RGB(255,0,0));
    pDC->SetPixel(101,101,RGB(255,0,0));
    pDC->SetPixel(99,100,RGB(255,0,0));
    pDC->SetPixel(100,99,RGB(255,0,0));
    pDC->SetPixel(99,99,RGB(255,0,0));
}

(3)在 OnDraw 函数中调用 DrawPoints 函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) {
    CExp_01Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    DrawPoints(pDC); //调用 DrawPoints 函数
}

(4)修改 DrawPoints 函数,绘制行政中心。代码如下:

void CExp_01View::DrawPoints(CDC *pDC) {
    /* //方法尝试,查看效果
    //Method_1:绘制邻近的点集,以突出显示
    pDC->SetPixel(100,100,RGB(255,0,0));
    ...
    //Method_2:使用 for 循环成实心方块,以突出显示
    for(int i=0; i<10; ++i) {
        for (int j=0; j<10; ++j) {
            pDC->SetPixel(200+j, 150+i, RGB(255,0,0));
        }
    }
    */
    //绘制行政中心
    for(int i=0; i<10; ++i) {
        for (int j=0; j<10; ++j) {
            //绘制 4 个实心方块,作行政中心
            pDC->SetPixel(200+j, 150+i, RGB(255,0,0));
            pDC->SetPixel(600+j, 150+i, RGB(0,255,0));
            pDC->SetPixel(350+j, 300+i, RGB(0,0,255));
            pDC->SetPixel(800+j, 400+i, RGB(200,100,100));
        }
    }
}

(5)调试运行,结果如下图 5 所示:

图 5 绘制行政中心

4.3 绘制线

(1)增加成员函数 DrawLines。

(2)编辑 DrawLines 函数。使用 LineTo 函数和 MoveTo 函数绘制实线的主干道,使用 SetPixel 函数 for 循环绘制虚线的支路,使用 Polyline 函数绘制折线的边界,使用 PolyBezierTo 函数与创建画笔绘制蓝色河流。代码如下:

void CExp_01View::DrawLines(CDC *pDC) {
    //实线主干道绘制:LineTo 函数和 MoveTo 函数
    pDC->MoveTo(50,250);
    POINT p1;p1.x=700;p1.y=250; //使用 POINT 结构
    pDC->LineTo(p1);
    CPoint p2;p2.x=1200;p2.y=20; //使用 CPoint 类
    pDC->LineTo(p2);
    pDC->MoveTo(50,270);
    pDC->LineTo(720,270);
    pDC->LineTo(1240,20);
    pDC->TextOut(600,260,_T("主干道")); //注记
    
    //虚线支路绘制:SetPixel 函数 for 循环
    for(int i=0;i<300;i=i+5) {
        pDC->SetPixel(500,270+i,RGB(255,0,0));
        pDC->SetPixel(520,270+i,RGB(255,0,0));
        pDC->TextOut(530,400,_T("支路")); //注记
    }
    
    //折线边界绘制:Polyline 函数
    POINT p[10];
    p[0].x=1100;p[0].y=400;
    p[1].x=1100;p[1].y=500;
    p[2].x=1200;p[2].y=500;
    p[3].x=1200;p[3].y=600;
    p[4].x=10;p[4].y=600;
    p[5].x=10;p[5].y=10;
    p[6].x=1250;p[6].y=10;
    p[7].x=1250;p[7].y=200;
    p[8].x=1100;p[8].y=200;
    p[9].x=1100;p[9].y=300;
    pDC->Polyline(p,10);
    pDC->TextOut(1100,350,_T("大门")); //注记
    
    //曲线河流绘制:PolyBezierTo 函数与创建画笔
    HPEN hPen = CreatePen(PS_SOLID, 3, RGB(0,0,255)); //创建蓝色画笔
    HPEN hOldPen = (HPEN)pDC->SelectObject(hPen); //把画笔选进 DC
    POINT n[6];
    pDC->MoveTo(200,100);
    n[0].x=200;n[0].y=200;
    n[1].x=300;n[1].y=200;
    n[2].x=400;n[2].y=300;
    n[3].x=500;n[3].y=400;
    n[4].x=300;n[4].y=400;
    n[5].x=100;n[5].y=450;
    pDC->PolyBezierTo(n,6); //六个点,两段连续
    pDC->SelectObject(hOldPen); //还原旧笔
    DeleteObject(hPen); //删除创建的画笔
    pDC->TextOut(220,110,_T("河流")); //注记
}

(3)在 OnDraw 函数中调用 DrawLines 函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) {
    CExp_01Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    DrawPoints(pDC); //调用 DrawPoints 函数
    DrawLines(pDC); //调用 DrawLines 函数
}

(4)调试运行,结果如下图 7 所示:

图 6 绘制道路与边界

4.4 绘制面

(1)增加成员函数 DrawPolygons。

(2)编辑 DrawPolygons 函数。使用 Rectangle 函数绘制行政中心范围,使用 RoundRect 函数绘制操场,使用 Ellipse 函数与创建画笔笔刷绘制湖泊。代码如下:

void CExp_01View::DrawPolygons(CDC *pDC) {
    // 1.绘制行政中心范围:Rectangle 函数
    //Method_1:使用对角坐标
    pDC->Rectangle(70,120,140,190);
    pDC->TextOut(70,200,_T("第一实验楼"));
    pDC->Rectangle(570,110,640,200);
    pDC->TextOut(570,210,_T("第一教学楼"));
    //Method_2:使用 CRect 类
    CRect r,h;
    r.left=330;r.top=280;
    r.right=380;r.bottom=330;
    h.left=760;h.top=360;
    h.right=850;h.bottom=450;
    pDC->Rectangle(r);
    pDC->TextOut(320,340,_T("第二教学楼"));
    pDC->Rectangle(h);
    pDC->TextOut(770,460,_T("第二实验楼"));
    
    // 2.绘制操场:RoundRect 函数
    pDC->RoundRect(230,450,450,580,30,30);
    pDC->RoundRect(240,460,440,570,30,30);
    pDC->TextOut(330,510,_T("操场"));
    
    // 3.绘制湖泊:Ellipse 函数与创建画笔笔刷
    HPEN hPen = CreatePen(PS_SOLID, 3, RGB(0,0,200)); //创建蓝色画笔
    HPEN hOldPen = (HPEN)pDC->SelectObject(hPen); //把画笔选进 DC
    HBRUSH hBrush = CreateSolidBrush(RGB(50,50,200)); //创建填充笔刷
    HBRUSH hOldBrush = (HBRUSH)pDC->SelectObject(hBrush); //把笔刷选进 DC
    CRect l;
    l.left=130;l.top=30;
    l.right=250;l.bottom=100;
    pDC->Ellipse(l);
    pDC->SelectObject(hOldPen); //还原旧笔
    DeleteObject(hPen); //删除创建的画笔
    pDC->SelectObject(hOldBrush); //还原原刷
    DeleteObject(hBrush); //删除创建的笔刷
    pDC->TextOut(260,60,_T("湖泊")); //注记
}

(3)在 OnDraw 函数中调用 DrawPolygons 函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) {
    CExp_01Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    DrawPolygons(pDC); //调用 DrawPolygons 函数
    DrawPoints(pDC); //调用 DrawPoints 函数
    DrawLines(pDC); //调用 DrawLines 函数
}

(4)调试运行,结果如下图 9 所示:

图 7 绘制面要素

4.5 绘制简易叶片图形

(1)增加成员函数 DrawLeaf。

(2)编辑 DrawLeaf 函数。使用画笔画刷绘制树叶颜色,Polygon 函数描摹俯视树叶投影的轮廓,并通过 MoveTo、LineTo 绘制折线树叶叶脉凸显三维效果。同时,使用 GetClientRect 获取视图中心,保证调整窗口大小而叶片能始终显示在客户区的中央。代码如下:

void CExp_01View::DrawLeaf(CDC *pDC, const CPoint &center) {
    CPen leafPen(PS_SOLID, 2, RGB(34, 139, 34)); // 树叶轮廓颜色
    CPen veinPen(PS_SOLID, 1, RGB(0, 100, 0)); // 叶脉颜色
    CBrush leafBrush(RGB(124, 252, 0)); // 树叶填充颜色
    CPen* pOldPen = pDC->SelectObject(&leafPen);
    CBrush* pOldBrush = pDC->SelectObject(&leafBrush);
    
    // 树叶轮廓点
    CPoint pts[7];
    pts[0] = CPoint(center.x, center.y - 40); // 叶尖
    pts[1] = CPoint(center.x - 20, center.y - 20);
    pts[2] = CPoint(center.x - 30, center.y);
    pts[3] = CPoint(center.x, center.y + 30); // 叶底
    pts[4] = CPoint(center.x + 30, center.y);
    pts[5] = CPoint(center.x + 20, center.y - 20);
    pts[6] = pts[0]; // 闭合
    pDC->Polygon(pts, 7); // 绘制叶脉
    pDC->SelectObject(&veinPen);
    pDC->MoveTo(center.x, center.y - 40);
    pDC->LineTo(center.x, center.y + 30); // 主脉
    pDC->MoveTo(center.x, center.y - 10);
    pDC->LineTo(center.x - 20, center.y - 5); // 左侧脉
    pDC->MoveTo(center.x, center.y - 10);
    pDC->LineTo(center.x + 20, center.y - 5); // 右侧脉
    
    // 恢复原始画笔和画刷
    pDC->SelectObject(pOldPen);
    pDC->SelectObject(pOldBrush);
}

(3)在 OnDraw 函数中调用 DrawLeaf 函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) {
    CExp_01Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    DrawPolygons(pDC); //调用 DrawPolygons 函数
    DrawPoints(pDC); //调用 DrawPoints 函数
    DrawLines(pDC); //调用 DrawLines 函数
    CRect rect;
    GetClientRect(&rect);
    CPoint center = rect.CenterPoint();
    DrawLeaf(pDC, center);
}

(4)调试运行,结果如下图 10 所示:

图 8 简易树叶投影绘制

总结

本次实验通过创建单文本的 MFC AppWizard 项目,并使用 MoveTo、LineTo、Polygon 等函数绘制简易的区域平面图,包括行政中心等点要素,道路、河流等线要素,湖泊、操场、建筑范围等面要素。同时,在实验过程中,尝试以不同的方式实现相同的效果或以尝试其他方式以提高代码撰写的效率。最后,通过绘制简易的叶片投影,并将其始终置于客户区的中央,使用 Polygon 等函数简化描摹树叶叶片以二维图像凸显三维效果,表示正射投影的图形表示。

后期采集的叶片数据可能以 .tex 等文件格式存储三维叶片数据,可创建结构体、数组等将其读取与临时储存,通过正射投影、透视投影等投影方式将其转换为二维点集数据,以便于映射在二维的屏幕坐标中显示绘制。同时平移坐标点,使数据显示在客户区的中央。为三维与二维的建模转换的学习奠定良好的启发效果。

参考文献

  1. 侯俊杰。深入浅出 MFC(第 2 版)[M]. 武汉:华中科技大学出版社,2001.

目录

  1. 实验目的和要求
  2. 基本原理
  3. 开发环境
  4. 实验步骤与结果
  5. 4.1 创建 MFC 项目
  6. 4.2 绘制点
  7. 4.3 绘制线
  8. 4.4 绘制面
  9. 4.5 绘制简易叶片图形
  10. 总结
  11. 参考文献
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • FPGA开发工具对比:Vivado、Quartus与ModelSim
  • OpenClaw 机器人抓取平台搭建全流程详解(万字长文解析)
  • 转行网络安全行业能提高收入吗?
  • OpenCode:终端 AI 编程助手使用指南
  • OpenCode 与 GitHub Copilot 生产环境落地对比评测
  • OpenCode 使用 GitHub Copilot 的计费陷阱与优化方案
  • 6 种常用自定义数据结构设计与实现技巧
  • 大语言模型超参数入门与调优指南
  • Cursor VSCode Remote SSH 登录与 AI 对话连接问题修复指南
  • 本地服务器部署Text generation并添加code llama实现远程多人协作
  • Discord 机器人创建与配置完整指南
  • 豆包与扣子 Coze 对比:字节两大 AI 平台如何选择
  • 前端蓝桥杯 Web 备考:AJAX 与 XMLHttpRequest 核心知识点及实战
  • VSCode 中关闭 GitHub Copilot 功能的方法
  • Windows 上安装 vLLM 的两种方法
  • Stable Diffusion 整合包安装与使用指南
  • 在 Cursor 中配置与使用 MCP 服务
  • FAST_LIO 与 FAST_LIO2 算法原理及 ROS2 环境复现
  • 无人机 5.8G 模拟图传电路设计与性能分析
  • 基于 NoMachine 实现 Windows 远程控制 Jetson Ubuntu 桌面

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online