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

上一节中鸡啄米讲了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. // 将数组m_nzValues的元素都初始化为0
  6. memset(m_nzValues, 0, sizeof(int) * POINT_COUNT);
  7. }

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

C++代码

  1. BOOL CExample50Dlg::OnInitDialog()
  2. {
  3. CDialogEx::OnInitDialog();
  4. // Add "About..." menu item to system menu.
  5. // IDM_ABOUTBOX must be in the system command range.
  6. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  7. ASSERT(IDM_ABOUTBOX < 0xF000);
  8. CMenu* pSysMenu = GetSystemMenu(FALSE);
  9. if (pSysMenu != NULL)
  10. {
  11. BOOL bNameValid;
  12. CString strAboutMenu;
  13. bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
  14. ASSERT(bNameValid);
  15. if (!strAboutMenu.IsEmpty())
  16. {
  17. pSysMenu->AppendMenu(MF_SEPARATOR);
  18. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  19. }
  20. }
  21. // Set the icon for this dialog.  The framework does this automatically
  22. //  when the application‘s main window is not a dialog
  23. SetIcon(m_hIcon, TRUE);         // Set big icon
  24. SetIcon(m_hIcon, FALSE);        // Set small icon
  25. // TODO: Add extra initialization here
  26. // 以时间为种子来构造随机数生成器
  27. srand((unsigned)time(NULL));
  28. // 启动定时器,ID为1,定时时间为200ms
  29. SetTimer(1, 200, NULL);
  30. return TRUE;  // return TRUE  unless you set the focus to a control
  31. }

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. // 计算fDeltaX和fDeltaY
  12. fDeltaX = (float)rectPicture.Width() / (POINT_COUNT - 1);
  13. fDeltaY = (float)rectPicture.Height() / 80;
  14. // 创建黑色新画刷
  15. newBrush.CreateSolidBrush(RGB(0,0,0));
  16. // 选择新画刷,并将旧画刷的指针保存到pOldBrush
  17. pOldBrush = pDC->SelectObject(&newBrush);
  18. // 以黑色画刷为绘图控件填充黑色,形成黑色背景
  19. pDC->Rectangle(rectPicture);
  20. // 恢复旧画刷
  21. pDC->SelectObject(pOldBrush);
  22. // 删除新画刷
  23. newBrush.DeleteObject();
  24. // 创建实心画笔,粗度为1,颜色为绿色
  25. newPen.CreatePen(PS_SOLID, 1, RGB(0,255,0));
  26. // 选择新画笔,并将旧画笔的指针保存到pOldPen
  27. pOldPen = pDC->SelectObject(&newPen);
  28. // 将当前点移动到绘图控件窗口的左下角,以此为波形的起始点
  29. pDC->MoveTo(rectPicture.left, rectPicture.bottom);
  30. // 计算m_nzValues数组中每个点对应的坐标位置,并依次连接,最终形成曲线
  31. for (int i=0; i<POINT_COUNT; i++)
  32. {
  33. nX = rectPicture.left + (int)(i * fDeltaX);
  34. nY = rectPicture.bottom - (int)(m_nzValues[i] * fDeltaY);
  35. pDC->LineTo(nX, nY);
  36. }
  37. // 恢复旧画笔
  38. pDC->SelectObject(pOldPen);
  39. // 删除新画笔
  40. newPen.DeleteObject();
  41. }

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. for (int i=0; i<POINT_COUNT-1; i++)
  7. {
  8. m_nzValues[i] = m_nzValues[i+1];
  9. }
  10. // 为最后一个元素赋一个80以内的随机数值(整型)
  11. m_nzValues[POINT_COUNT-1] = rand() % 80;
  12. // 获取绘图控件的客户区坐标
  13. // (客户区坐标以窗口的左上角为原点,这区别于以屏幕左上角为原点的屏幕坐标)
  14. m_picDraw.GetClientRect(&rectPicture);
  15. // 绘制波形图
  16. DrawWave(m_picDraw.GetDC(), rectPicture);
  17. CDialogEx::OnTimer(nIDEvent);
  18. }

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

C++代码

  1. void CExample50Dlg::OnDestroy()
  2. {
  3. CDialogEx::OnDestroy();
  4. // TODO: Add your message handler code here
  5. // 关闭定时器
  6. KillTimer(1);
  7. }

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

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

原文地址:http://www.jizhuomi.com/software/246.html

时间: 2024-10-03 05:13:27

(转载)VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen)的相关文章

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

上一节中鸡啄米讲了CDC类及其屏幕绘图函数,本节的主要内容是GDI对象之画笔CPen. GDI对象 在MFC中,CGdiObject类是GDI对象的基类,通过查阅MSDN我们可以看到,CGdiObject类有六个直接的派生类,GDI对象主要也是这六个,分别是:CBitmap.CBrush.CFont.CPalette.CPen和CRgn. 在这六个GDI对象中,最常用的莫过于画笔和画刷了,即CPen类和CBrush类.本文就主要讲解画笔的使用. 画笔的应用实例 鸡啄米在这里直接通过一个波形图的实

(转载)VS2010/MFC编程入门之五十二(Ribbon界面开发:创建Ribbon样式的应用程序框架)

上一节中鸡啄米讲了GDI对象之画刷CBrush,至此图形图像的入门知识就讲完了.从本节开始鸡啄米将为大家带来Ribbon界面开发的有关内容.本文先来说说如何创建Ribbon样式的应用程序框架. Ribbon界面就是微软从Office2007开始引入的一种为了使应用程序的功能更加易于发现和使用.减少了点击鼠标的次数的新型界面,从实际效果来看,不仅外观漂亮,而且功能直观,用户操作简洁方便. 鸡啄米将以图文结合的方式来说明利用MFC向导创建Ribbon样式的单文档应用程序框架的过程,其实Ribbon应

VS2010/MFC编程入门之五十二(Ribbon界面开发:创建Ribbon样式的应用程序框架)

上一节中鸡啄米讲了GDI对象之画刷CBrush,至此图形图像的入门知识就讲完了.从本节开始鸡啄米将为大家带来Ribbon界面开发的有关内容.本文先来说说如何创建Ribbon样式的应用程序框架. Ribbon界面就是微软从Office2007开始引入的一种为了使应用程序的功能更加易于发现和使用.减少了点击鼠标的次数的新型界面,从实际效果来看,不仅外观漂亮,而且功能直观,用户操作简洁方便. 鸡啄米将以图文结合的方式来说明利用MFC向导创建Ribbon样式的单文档应用程序框架的过程,其实Ribbon应

VS2010/MFC编程入门之五十四(Ribbon界面开发:使用更多控件并为控件添加消息处理函数)

http://www.jizhuomi.com/software/255.html 上一节中鸡啄米讲了为Ribbon Bar添加控件的方法.本节教程鸡啄米将继续完善前面的实例,讲解一些稍复杂的控件的添加方法,及如何为它们添加消息处理函数. 一.为Ribbon Bar添加更多Ribbon控件 鸡啄米将在上一节实例的基础上,继续添加下拉菜单.Check Box.Combo Box等Ribbon控件. 1.首先把“Small Button”面板上的“Click”按钮改造成一个下拉菜单.“Click”按

VS2010/MFC编程入门之五(MFC消息映射机制概述)

VS2010/MFC编程入门之五(MFC消息映射机制概述)-软件开发-鸡啄米 http://www.jizhuomi.com/software/147.html     上一讲鸡啄米为大家简单分析了MFC应用程序框架,这一讲是关于MFC消息映射机制的内容.        前面已经说过,Windows应用程序是消息驱动的.在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的

(转载)VS2010/MFC编程入门之五十一(图形图像:GDI对象之画刷CBrush)

上一节中鸡啄米主要讲的是画笔CPen的用法,前面也说了,GDI对象中最常用的就是画笔和画刷,本节就讲讲画刷CBrush. 鸡啄米依然是通过实例的方式来说明画刷的用法.此实例要实现的功能是,对话框上有一个按钮控件和一个图片控件,点击按钮弹出颜色对话框,然后在颜色对话框中选择颜色并点击"确定"后,图片控件中将显示选择的颜色. 其实此实例的功能,还可以通过重载对话框WM_CTLCOLOR消息的响应函数等方法来实现,但为讲解画刷的CBrush的使用,鸡啄米采用了下面代码中的方法. 以下是此实例

(转载)VS2010/MFC编程入门之十九(对话框:颜色对话框)

鸡啄米在上一节中为大家讲解了字体对话框的使用方法,熟悉了字体对话框,本节继续讲另一种通用对话框--颜色对话框. 颜色对话框大家肯定也不陌生,我们可以打开它选择需要的颜色,简单说,它的作用就是用来选择颜色.MFC中提供了CColorDialog类封装了颜色对话框的所有操作,我们可以通过它显示颜色对话框,并获取颜色对话框中选择的颜色.颜色对话框跟字体对话框一样,也是一种模态对话框. CColorDialog类的构造函数 CColorDialog(   COLORREF clrInit = 0,  

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

上一节中鸡啄米主要讲的是画笔CPen的用法,前面也说了,GDI对象中最常用的就是画笔和画刷,本节就讲讲画刷CBrush. 鸡啄米依然是通过实例的方式来说明画刷的用法.此实例要实现的功能是,对话框上有一个按钮控件和一个图片控件,点击按钮弹出颜色对话框,然后在颜色对话框中选择颜色并点击"确定"后,图片控件中将显示选择的颜色. 其实此实例的功能,还可以通过重载对话框WM_CTLCOLOR消息的响应函数等方法来实现,但为讲解画刷的CBrush的使用,鸡啄米采用了下面代码中的方法. 以下是此实例

(转载)VS2010/MFC编程入门之十八(对话框:字体对话框)

鸡啄米在上一节为大家讲解了文件对话框的使用,本节则主要介绍字体对话框如何应用. 字体对话框的作用是用来选择字体.我们也经常能够见到.MFC使用CFontDialog类封装了字体对话框的所有操作.字体对话框也是一种模态对话框. CFontDialog类的构造函数 我们先来了解CFontDialog类.它的常用构造函数原型如下: CFontDialog(   LPLOGFONT lplfInitial = NULL,   DWORD dwFlags = CF_EFFECTS | CF_SCREENF