热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen)

上一节中鸡啄米讲了CDC类及其屏幕绘图函数,本节的主要内容是GDI对象之画笔CPen。       GDI对象       在MFC中,CGdiObject类是GDI对象的基类,通

上一节中鸡啄米讲了CDC类及其屏幕绘图函数,本节的主要内容是GDI对象之画笔CPen。

       GDI对象

       在MFC中,CGdiObject类是GDI对象的基类,通过查阅MSDN我们可以看到,CGdiObject类有六个直接的派生类,GDI对象主要也是这六个,分别是:CBitmap、CBrush、CFont、CPalette、CPen和CRgn。

       在这六个GDI对象中,最常用的莫过于画笔和画刷了,即CPen类和CBrush类。本文就主要讲解画笔的使用。

       画笔的应用实例

       鸡啄米在这里直接通过一个波形图的实例,来详细讲解画笔的使用方法。

       首先介绍此实例要实现的功能:在对话框上有一个Picture控件,将此控件的背景填充为黑色;启动一个定时器,每次定时器到时,所有波形数据都前移一个单位,并获取一个80以内的随机数作为波形的最后一个数据,然后以绿色画笔在绘图控件上绘制波形。这样就实现了波形的绘制及动态变化。

       下面是具体实施步骤:

       1、创建一个基于对话框的MFC工程,名字设为“Example50”。

       2、在自动生成的对话框模板IDD_EXAMPLE50_DIALOG中,删除“TODO: Place dialog controls here.”静态文本框,添加一个Picture控件,ID设为IDC_WAVE_DRAW。 

       3、为Picture控件IDC_WAVE_DRAW添加CStatic变量,名称设为m_picDraw。

       4、在文件Example50Dlg.h文件中CExample50Dlg类声明的上面添加宏定义:


C++代码

  1. #define POINT_COUNT 100  

       此符号常量的意义是波形的点数,这里用define将其定义为符号常量是为了方便以后可能的修改,假如我们以后想将点数改为200,则只改此宏定义就可以了:#define POINT_COUNT 200,而如果没有使用符号常量,在程序中直接使用了100,那么就需要将所有使用100的位置找出来,并替换为200,这样不仅麻烦也很容易出错,所以最好是将其定义为符号常量。

       5、在CExample50Dlg.h文件中为CExample50Dlg类添加成员数组:


C++代码

  1. int   m_nzValues[POINT_COUNT];  

       此数组用于存放波形数据。

       6、在CExample50Dlg类的构造函数中为数组m_nzValues的元素赋初值:


C++代码

  1. CExample50Dlg::CExample50Dlg(CWnd* pParent /*=NULL*/)   

  2.     : CDialogEx(CExample50Dlg::IDD, pParent)   

  3. {   

  4.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);   

  5.   

  6.     // 将数组m_nzValues的元素都初始化为0   

  7.     memset(m_nzValues, 0, sizeof(int) * POINT_COUNT);   

  8. }  

       7、在CExample50Dlg对话框的初始化成员函数CExample50Dlg::OnInitDialog()中,构造随机数生成器,并启动定时器。CExample50Dlg::OnInitDialog()修改如下:


C++代码

  1. BOOL CExample50Dlg::OnInitDialog()   

  2. {   

  3.     CDialogEx::OnInitDialog();   

  4.   

  5.     // Add "About..." menu item to system menu.   

  6.   

  7.     // IDM_ABOUTBOX must be in the system command range.   

  8.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);   

  9.     ASSERT(IDM_ABOUTBOX < 0xF000);   

  10.   

  11.     CMenu* pSysMenu = GetSystemMenu(FALSE);   

  12.     if (pSysMenu != NULL)   

  13.     {   

  14.         BOOL bNameValid;   

  15.         CString strAboutMenu;   

  16.         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);   

  17.         ASSERT(bNameValid);   

  18.         if (!strAboutMenu.IsEmpty())   

  19.         {   

  20.             pSysMenu->AppendMenu(MF_SEPARATOR);   

  21.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);   

  22.         }   

  23.     }   

  24.   

  25.     // Set the icon for this dialog.  The framework does this automatically   

  26.     //  when the application's main window is not a dialog   

  27.     SetIcon(m_hIcon, TRUE);         // Set big icon   

  28.     SetIcon(m_hIcon, FALSE);        // Set small icon   

  29.   

  30.     // TODO: Add extra initialization here   

  31.   

  32.     // 以时间为种子来构造随机数生成器   

  33.     srand((unsigned)time(NULL));   

  34.   

  35.     // 启动定时器,ID为1,定时时间为200ms   

  36.     SetTimer(1, 200, NULL);   

  37.   

  38.     return TRUE;  // return TRUE  unless you set the focus to a control   

  39. }  

       8、为CExample50Dlg类添加波形绘制的成员函数CExample50Dlg::DrawWave(CDC *pDC, CRect &rectPicture),参数分别为设备上下文指针和绘图的矩形区域。


C++代码

  1. void CExample50Dlg::DrawWave(CDC *pDC, CRect &rectPicture)   

  2. {   

  3.     float fDeltaX;     // x轴相邻两个绘图点的坐标距离   

  4.     float fDeltaY;     // y轴每个逻辑单位对应的坐标值   

  5.     int nX;      // 在连线时用于存储绘图点的横坐标   

  6.     int nY;      // 在连线时用于存储绘图点的纵坐标   

  7.     CPen newPen;       // 用于创建新画笔   

  8.     CPen *pOldPen;     // 用于存放旧画笔   

  9.     CBrush newBrush;   // 用于创建新画刷   

  10.     CBrush *pOldBrush; // 用于存放旧画刷   

  11.   

  12.     // 计算fDeltaX和fDeltaY   

  13.     fDeltaX = (float)rectPicture.Width() / (POINT_COUNT - 1);   

  14.     fDeltaY = (float)rectPicture.Height() / 80;   

  15.   

  16.     // 创建黑色新画刷   

  17.     newBrush.CreateSolidBrush(RGB(0,0,0));   

  18.     // 选择新画刷,并将旧画刷的指针保存到pOldBrush   

  19.     pOldBrush = pDC->SelectObject(&newBrush);   

  20.     // 以黑色画刷为绘图控件填充黑色,形成黑色背景   

  21.     pDC->Rectangle(rectPicture);   

  22.     // 恢复旧画刷   

  23.     pDC->SelectObject(pOldBrush);   

  24.     // 删除新画刷   

  25.     newBrush.DeleteObject();   

  26.   

  27.     // 创建实心画笔,粗度为1,颜色为绿色   

  28.     newPen.CreatePen(PS_SOLID, 1, RGB(0,255,0));   

  29.     // 选择新画笔,并将旧画笔的指针保存到pOldPen   

  30.     pOldPen = pDC->SelectObject(&newPen);   

  31.   

  32.     // 将当前点移动到绘图控件窗口的左下角,以此为波形的起始点   

  33.     pDC->MoveTo(rectPicture.left, rectPicture.bottom);   

  34.     // 计算m_nzValues数组中每个点对应的坐标位置,并依次连接,最终形成曲线   

  35.     for (int i=0; i


  36.     {   

  37.         nX = rectPicture.left + (int)(i * fDeltaX);   

  38.         nY = rectPicture.bottom - (int)(m_nzValues[i] * fDeltaY);   

  39.         pDC->LineTo(nX, nY);   

  40.     }   

  41.   

  42.     // 恢复旧画笔   

  43.     pDC->SelectObject(pOldPen);   

  44.     // 删除新画笔   

  45.     newPen.DeleteObject();   

  46. }  

       9、有了定时器和绘图成员函数,我们就可以在WM_TIMER消息的响应函数中添加对波形数据的定时处理和对波形的定时绘制了。定时器及WM_TIMER消息处理函数的添加方法如果忘记了,可以再到VS2010/MFC编程入门之四十四(MFC常用类:定时器Timer)温习下。

       WM_TIMER消息的处理函数修改如下:


C++代码

  1. void CExample50Dlg::OnTimer(UINT_PTR nIDEvent)   

  2. {   

  3.     // TODO: Add your message handler code here and/or call default   

  4.     CRect rectPicture;   

  5.   

  6.     // 将数组中的所有元素前移一个单位,第一个元素丢弃   

  7.     for (int i=0; i


  8.     {   

  9.         m_nzValues[i] = m_nzValues[i+1];   

  10.     }   

  11.     // 为最后一个元素赋一个80以内的随机数值(整型)   

  12.     m_nzValues[POINT_COUNT-1] = rand() % 80;   

  13.   

  14.     // 获取绘图控件的客户区坐标   

  15.     // (客户区坐标以窗口的左上角为原点,这区别于以屏幕左上角为原点的屏幕坐标)   

  16.     m_picDraw.GetClientRect(&rectPicture);   

  17.   

  18.     // 绘制波形图   

  19.     DrawWave(m_picDraw.GetDC(), rectPicture);   

  20.   

  21.     CDialogEx::OnTimer(nIDEvent);   

  22. }  

       10、在对话框销毁时,定时器应关闭。所以为CExample50Dlg类添加WM_DESTROY消息的处理函数,并修改如下:


C++代码

  1. void CExample50Dlg::OnDestroy()   

  2. {   

  3.     CDialogEx::OnDestroy();   

  4.   

  5.     // TODO: Add your message handler code here   

  6.   

  7.     // 关闭定时器   

  8.     KillTimer(1);   

  9. }  

       11、一切准备就绪,编译运行。最终的效果如下图:

VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen)

VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen)

       关于画笔,鸡啄米就讲到这里了,下一节将为大家简单讲讲画刷的使用。谢谢大家的关注!


 
 
转自:http://www.jizhuomi.com/software/181.html

推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 多维数组的使用
    本文介绍了多维数组的概念和使用方法,以及二维数组的特点和操作方式。同时还介绍了如何获取数组的长度。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • WPF开发心率检测大数据曲线图的高性能实现方法
    本文介绍了在WPF开发中实现心率检测大数据曲线图的高性能方法。作者尝试过使用Canvas和第三方开源库,但性能和功能都不理想。最终作者选择使用DrawingVisual对象,并结合局部显示的方式实现了自己想要的效果。文章详细介绍了实现思路和具体代码,对于不熟悉DrawingVisual的读者可以去微软官网了解更多细节。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
author-avatar
w50251898
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有