MFC--根据串口采集的数据借助GDI绘制曲线

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC--根据串口采集的数据借助GDI绘制曲线相关的知识,希望对你有一定的参考价值。

根据采集到的数据绘制曲线

在串口编程中会涉及到这样一个问题,就是将采集到的数据以曲线的形式展示出来,大家自然而然会想到采用方便快捷的控件进行编程。编程周期短,完成任务快,但是真实情况来看,控件会实现很多你用不到的功能,实现机制也不可见,这样在功能上会造成浪费,对性能和实现的效果上会有一些不可控,所以在这一类编程中建议自己通过设备上下文自己编写适合自己软件的曲线图。

我要实现的功能如下图:

 

这是一个在网上下载的例程运行的效果,我中间采用的编程思想大多来源这里,只是针我要实现的功能进行了修改。因为我的程序现在还没进行设备测试,所以这里借用一下这个效果图。

将画图实现的功能封装在一个类里面,在需要画图的时候,便可以实例化一个对象。

下面是详细的实现过程,为防止屏幕闪烁,采用了双缓冲技术。

实现的过程中主要的两问题是:1、为了绘制速度快,不会因为数据的增加而出现绘制越来越慢,最后卡死的现象,这里采用例程中用的方法,将已经画过的图像保存BitMap 中,来了数据直接在map上绘制,然后再复制在屏幕上。2、我的功能中会根据用户操作改变曲线显示的区域大小,这个时候就需要全部重绘,原来map里的曲线就不能再用了,因为大小已经改变了,这时候在OnPaint函数里面实现的功能就是重新绘制坐标轴框图和根据保存的数据进行曲线的绘制。

该类的头文件函数:

技术分享
  1 #pragma once
  2 
  3 
  4 
  5 //用于绘制二维曲线
  6 class CDrawView : public CWnd
  7 {
  8     DECLARE_DYNCREATE(CDrawView)
  9 
 10 public:
 11     CDrawView();        
 12     virtual ~CDrawView();
 13     DECLARE_MESSAGE_MAP()
 14 
 15 public:
 16 #ifdef _DEBUG
 17     virtual void AssertValid() const;
 18 #ifndef _WIN32_WCE
 19     virtual void Dump(CDumpContext& dc) const;
 20 #endif
 21 #endif
 22 
 23 public:
 24 
 25 
 26 
 27     CPoint m_dCurrentPosition;     //current position
 28     CPoint m_dPreviousPosition;     //previous position
 29     double m_updateRate;//数据更新率
 30     void setUpdateRate(double updateRate);
 31 
 32     CList<CPoint,CPoint&> dataList;//用于存储真实数据
 33     CList<CPoint,CPoint&> dataList1;//用于绘图
 34     CList<CPoint,CPoint&> tempDataList;//暂存数据
 35     void InvalidateCtrl();
 36     void SetYRange(double dYLower, double dYUpper, int nYDecimalPlaces);
 37     void SetXRange(int dXLower,int dXUpper,int nXDecimalPlaces);
 38     void SetXUnits(CString string);
 39     void SetYUnits(CString string);
 40     void SetGridColor(COLORREF color);
 41     void SetPlotColor(COLORREF color);
 42     void SetBackgroundColor(COLORREF color);
 43     void SetTitle(CString title);
 44     void AppendPoint(CPoint *newDataList);
 45     void Reset();
 46     void DrawPoint();
 47 
 48     //各个部分的颜色
 49     COLORREF m_crBackColor;     //backGround color
 50     COLORREF m_crGridColor;     //Grid color
 51     COLORREF m_crPlotColor;     //data plot color
 52 
 53     //设备上下文以及与其相关的位图
 54 
 55     CDC m_dcGrid;
 56     CDC m_dcPlot;
 57     CBitmap *m_pBitmapOldGrid;
 58     CBitmap *m_pBitmapOldPlot;
 59     CBitmap m_pBitmapGrid;
 60     CBitmap m_pBitmapPlot;
 61 
 62 
 63     //画图区域相关
 64     int m_nHalfShiftPixels;
 65     int m_nPlotShiftPixels;
 66     int m_nClientHeight;
 67     int m_nClientWidth;
 68     int m_nPlotHeight;
 69     int m_nPlotWidth;
 70 
 71     //坐标轴Y
 72     double m_dYLowerLimit;
 73     double m_dYUpperLimit;
 74     double m_dYRange;
 75     double m_dVerticalFactor;
 76 
 77     //坐标轴X
 78     int m_dXLowerLimit;
 79     int m_dXUpperLimit;
 80     double m_dXRange;
 81     double m_dHorizontalFactor;
 82 
 83     //title
 84     CString m_sTitile;
 85 
 86     CRect m_rectClient;
 87     CRect m_rectPlot;
 88     CPen  m_penPlot;
 89     CBrush m_brushBack;
 90 
 91     int m_nShiftPixels;          //amount  to  shift with each new point 
 92     int m_nYDecimal;
 93     int m_nXDecimal;
 94 
 95     CString m_strXUnitsString;
 96     CString m_strYUnitsString;
 97 
 98 
 99 
100 
101     CString str;
102     CList<int,int>listOfFogX;
103 
104     afx_msg void OnPaint();
105     BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID=NULL);
106     afx_msg void OnSize(UINT nType, int cx, int cy);
107 };
View Code

 

该类的实现文件内容:

技术分享
  1 // DrawView.cpp : 实现文件
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "IMU4.h"
  6 #include "DrawView.h"
  7 #include "math.h"
  8 
  9 
 10 // CDrawView
 11 
 12 IMPLEMENT_DYNCREATE(CDrawView, CWnd)
 13 
 14 CDrawView::CDrawView()
 15 {
 16     m_nYDecimal = 3 ;
 17 
 18     m_dPreviousPosition.x = 0;
 19     m_dPreviousPosition.y = 0;
 20 
 21     m_dCurrentPosition.x = 0;
 22     m_dCurrentPosition.y = 0;
 23 
 24     m_dYLowerLimit = -10.0 ;
 25     m_dYUpperLimit =  10.0 ;
 26     m_dYRange =  m_dYUpperLimit - m_dYLowerLimit ;   
 27 
 28     m_dXLowerLimit = 0;
 29     m_dXUpperLimit = 1000;
 30     m_dXRange = m_dXUpperLimit - m_dXLowerLimit;
 31 
 32     m_dVerticalFactor = (double)m_nPlotHeight / m_dYRange ; 
 33     m_dHorizontalFactor = (double)m_nClientWidth / m_dXRange / 100.0;
 34 
 35     m_nShiftPixels     = 4 ;
 36     m_nHalfShiftPixels = m_nShiftPixels/2 ;                     
 37     m_nPlotShiftPixels = m_nShiftPixels + m_nHalfShiftPixels ;  
 38 
 39     m_crBackColor  = RGB(  0,   0,   0) ;  
 40     m_crGridColor  = RGB(  0, 255, 255) ;  
 41     m_crPlotColor  = RGB(255, 255, 255) ;  
 42 
 43     m_penPlot.CreatePen(PS_SOLID, 0, m_crPlotColor) ;
 44     m_brushBack.CreateSolidBrush(m_crBackColor) ;
 45 
 46     m_strXUnitsString.Format(_T("")) ;  
 47     m_strYUnitsString.Format(_T("")) ;  
 48 
 49     m_pBitmapOldGrid = NULL ;
 50 }
 51 
 52 CDrawView::~CDrawView()
 53 {
 54 
 55 }
 56 
 57 
 58 BEGIN_MESSAGE_MAP(CDrawView, CWnd)
 59     ON_WM_MOUSEACTIVATE()
 60     ON_WM_DESTROY()
 61     ON_WM_PAINT()
 62     ON_WM_SIZE()
 63     ON_WM_TIMER()
 64 END_MESSAGE_MAP()
 65 
 66 
 67 
 68 #ifdef _DEBUG
 69 void CDrawView::AssertValid() const
 70 {
 71     CWnd::AssertValid();
 72 }
 73 
 74 #ifndef _WIN32_WCE
 75 void CDrawView::Dump(CDumpContext& dc) const
 76 {
 77     CWnd::Dump(dc);
 78 }
 79 #endif
 80 #endif
 81 void CDrawView::InvalidateCtrl()
 82 {
 83     //用于画坐标轴等信息的函数
 84     int i;
 85     int nCharacters;
 86     int nTopGridPix,nMidGridPix,nBottomGridPix;//分别代表绘图区的三条线(暂定)
 87 
 88     CPen *oldPen;
 89     CPen solidPen(PS_SOLID,0,m_crGridColor);//建立一个画实线的画笔对象
 90     CFont axisFont,yUnitFont,*oldFont;//建立三个字体对象
 91     CString strTemp = _T("0");
 92 
 93     CClientDC dc(this);
 94     if(m_dcGrid.GetSafeHdc() == NULL)
 95     {
 96         m_dcGrid.CreateCompatibleDC(&dc);    
 97         m_pBitmapGrid.CreateCompatibleBitmap(&dc,m_nClientWidth,m_nClientHeight);    
 98         m_pBitmapOldGrid = m_dcGrid.SelectObject(&m_pBitmapGrid);
 99     }
100     m_dcGrid.SetBkColor(m_crBackColor);
101     m_dcGrid.FillRect(m_rectClient, &m_brushBack) ;    
102     nCharacters = max(abs((int)log10(fabs(m_dYUpperLimit))),abs((int)log10(fabs(m_dYLowerLimit))));
103     nCharacters = nCharacters + 4 + m_nYDecimal;
104 
105     m_rectPlot.left = m_rectClient.left + 6 * nCharacters;
106     m_nPlotWidth = m_rectPlot.Width();
107 
108     //draw the plot rectangle
109     oldPen = m_dcGrid.SelectObject(&solidPen);
110     m_dcGrid.MoveTo(m_rectPlot.left,m_rectPlot.top);
111     m_dcGrid.LineTo(m_rectPlot.right + 1,m_rectPlot.top);
112     m_dcGrid.LineTo(m_rectPlot.right + 1,m_rectPlot.bottom + 1);
113     m_dcGrid.LineTo(m_rectPlot.left,m_rectPlot.bottom + 1);
114     m_dcGrid.LineTo(m_rectPlot.left,m_rectPlot.top);
115 
116     //draw the dotted lines,
117     //use setPixel instead of a dotted pen - this allows for a 
118     //finer  dotted line  and a more "" technical "look
119     nMidGridPix = (m_rectPlot.top + m_rectPlot.bottom) / 2;
120     nTopGridPix = nMidGridPix - m_nPlotHeight / 4;
121     nBottomGridPix = nMidGridPix + m_nPlotHeight / 4;
122 
123     for(i = m_rectPlot.left; i < m_rectPlot.right; i+= 4)
124     {
125         m_dcGrid.SetPixel(i,nTopGridPix,m_crGridColor);
126         m_dcGrid.SetPixel(i,nMidGridPix,m_crGridColor);
127         m_dcGrid.SetPixel(i,nBottomGridPix,m_crGridColor);
128     }
129 
130     //create some fonts (horiaontal  and vertical )
131     //use a height  of 14 pixels and 300 weight
132     //(this may need  to be adjusted depending on the display )
133 
134     axisFont.CreateFont (14, 0, 0, 0, 300,
135                        FALSE, FALSE, 0, ANSI_CHARSET,
136                        OUT_DEFAULT_PRECIS, 
137                        CLIP_DEFAULT_PRECIS,
138                        DEFAULT_QUALITY, 
139                        DEFAULT_PITCH|FF_SWISS, _T("Arial"));
140     yUnitFont.CreateFont (14, 0, 900, 0, 300,
141                        FALSE, FALSE, 0, ANSI_CHARSET,
142                        OUT_DEFAULT_PRECIS, 
143                        CLIP_DEFAULT_PRECIS,
144                        DEFAULT_QUALITY, 
145                        DEFAULT_PITCH|FF_SWISS, _T("Arial")) ;
146 
147     //grab the horizontal font
148     oldFont = m_dcGrid.SelectObject(&axisFont);
149 
150     //y max
151     m_dcGrid.SetTextColor(m_crGridColor);
152     m_dcGrid.SetTextAlign(TA_RIGHT|TA_TOP);
153     strTemp.Format (_T("%.*lf"),m_nYDecimal, m_dYUpperLimit) ;//*号会被m_nYDecimals取代,表示保留几位小数
154     m_dcGrid.TextOutW(m_rectPlot.left - 4,m_rectPlot.top,strTemp);
155 
156     m_dcGrid.SetTextAlign (TA_LEFT|TA_TOP) ;
157     m_dcGrid.TextOut (m_rectPlot.left - 4, m_rectPlot.bottom - (0 - m_dYLowerLimit) * m_dVerticalFactor, _T("0")) ;
158     //y min 
159     m_dcGrid.SetTextAlign(TA_RIGHT|TA_BASELINE);
160     strTemp.Format(_T("%.*lf"),m_nYDecimal,m_dYLowerLimit);
161     m_dcGrid.TextOutW(m_rectPlot.left - 4,m_rectPlot.bottom,strTemp);
162 
163     //x min
164     m_dcGrid.SetTextAlign (TA_LEFT|TA_TOP) ;
165     m_dcGrid.TextOut (m_rectPlot.left, m_rectPlot.bottom+4, _T("0")) ;
166     //横坐标
167     for(int i = 1;i <= 5;i++)
168     {
169         m_dcGrid.SetTextAlign(TA_CENTER|TA_TOP);
170         strTemp.Format(_T("%d"),m_dXUpperLimit * i / 6);
171         m_dcGrid.TextOut((m_rectPlot.left + m_nPlotWidth * i / 6),m_rectPlot.bottom + 4, strTemp);
172     }
173     // x max
174      m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP) ;
175      strTemp.Format (_T("%d"), m_dXUpperLimit) ; 
176      m_dcGrid.TextOut (m_rectPlot.right, m_rectPlot.bottom+4, strTemp) ;
177 
178      // x units
179     m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP) ;
180     m_dcGrid.TextOut (m_rectPlot.right - 70, 
181                     m_rectPlot.bottom+4, m_strXUnitsString) ;
182     //title
183     m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP) ;
184     m_dcGrid.TextOut ((m_rectPlot.left+m_rectPlot.right)/2, 
185         m_rectPlot.top-17, m_sTitile) ;
186 
187     // restore the font
188     m_dcGrid.SelectObject(oldFont) ;
189     // y units
190     oldFont = m_dcGrid.SelectObject(&yUnitFont) ;
191     m_dcGrid.SetTextAlign (TA_CENTER|TA_BASELINE) ;
192     m_dcGrid.TextOut ((m_rectClient.left+m_rectPlot.left)/2, 
193                     (m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString) ;
194     m_dcGrid.SelectObject(oldFont) ;
195 
196     //创建画曲线的内存DC和兼容Bitmap
197     if (m_dcPlot.GetSafeHdc() == NULL)
198     {
199         m_dcPlot.CreateCompatibleDC(&dc) ;
200         m_pBitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;
201         m_pBitmapOldPlot = m_dcPlot.SelectObject(&m_pBitmapPlot) ;
202     }
203     // make sure the plot bitmap is cleared
204     m_dcPlot.SetBkColor (m_crBackColor) ;
205     m_dcPlot.FillRect(m_rectClient, &m_brushBack) ;
206 }
207 
208 //set title
209 void CDrawView::SetTitle(CString title)
210 {
211     m_sTitile = title;
212     InvalidateCtrl();
213 }
214 void CDrawView::SetYRange(double dYLower, double dYUpper, int nYDecimalPlaces)
215 {
216   ASSERT(dYUpper > dYLower) ;
217 
218   m_dYLowerLimit     = dYLower ;
219   m_dYUpperLimit     = dYUpper ;
220   m_nYDecimal      = nYDecimalPlaces ;
221   m_dYRange          = m_dYUpperLimit - m_dYLowerLimit ;
222   m_dVerticalFactor = (double)m_nPlotHeight / m_dYRange ; 
223 
224   InvalidateCtrl() ;
225 } // SetYRange
226 
227 void CDrawView::SetXRange(int dXLower,int dXUpper,int nXDecimalPlaces)
228 {
229     ASSERT(dXUpper > dXLower);
230 
231     m_dXLowerLimit = dXLower;
232     m_dXUpperLimit = dXUpper;
233     m_nXDecimal = nXDecimalPlaces;
234     m_dXRange = m_dXUpperLimit - m_dXLowerLimit;
235     m_dHorizontalFactor = (double)m_nPlotWidth / m_dXRange / 400.0 /** (m_updateRate * 400)*/;
236 
237     InvalidateCtrl();
238 }
239 
240 void CDrawView::SetXUnits(CString string)
241 {
242     m_strXUnitsString = string ;
243     InvalidateCtrl() ;
244 
245 }  // SetXUnits
246 
247 
248 void CDrawView::SetYUnits(CString string)
249 {
250     m_strYUnitsString = string ;
251     InvalidateCtrl() ;
252 
253 }  // SetYUnits
254 
255 void CDrawView::SetGridColor(COLORREF color)
256 {
257     m_crGridColor = color ;
258     InvalidateCtrl() ;
259 
260 }  // SetGridColor
261 
262 void CDrawView::SetPlotColor(COLORREF color)
263 {
264     m_crPlotColor = color ;
265 
266     m_penPlot.DeleteObject() ;
267     m_penPlot.CreatePen(PS_SOLID, 0, m_crPlotColor) ;
268     InvalidateCtrl() ;
269 
270 }  // SetPlotColor
271 
272 void CDrawView::SetBackgroundColor(COLORREF color)
273 {
274     m_crBackColor = color ;
275 
276     m_brushBack.DeleteObject() ;
277     m_brushBack.CreateSolidBrush(m_crBackColor) ;
278     InvalidateCtrl() ;
279 
280 }  // SetBackgroundColor
281 
282 void CDrawView::AppendPoint(CPoint *newpPoint)
283 {
284     //在plotBitmap上继续画刚接收到的一个数据点,如果一次画本次接收到的所有数据,耗时严重,实时性不强
285     CPoint dPrevious;
286     
287     dPrevious = m_dCurrentPosition;
288     m_dCurrentPosition = *newpPoint;
289     //根据新来的数据点更新纵坐标
290     if(m_dCurrentPosition.y < m_dYLowerLimit)
291     {
292         m_dYLowerLimit = m_dCurrentPosition.y;
293     }
294     if(m_dCurrentPosition.y > m_dYUpperLimit)
295     {
296         m_dYUpperLimit = m_dCurrentPosition.y;
297     }
298     //将数据保存在链表里用于重绘以及后面的参数计算
299     dataList.AddTail(m_dCurrentPosition);
300     //在plotBitmap上接着画当前数据点
301     DrawPoint();
302     //在界面上显示出来
303     //在这里要注意CClientDC和CPaintDC的区别,一定要避免在OnPaint函数里直接或间接的用CClientDC,这样会使界面一直重绘,造成假死现象
304     if(IsWindow(this->m_hWnd))
305     {
306         CClientDC dc(this) ;  // device context for painting
307         CDC memDC ;            //定义一个内存设备描述表对象(即后备缓冲区)
308         CBitmap memBitmap ;    //定义一个位图对象
309         CBitmap* oldBitmap ; // bitmap originally found in CMemDC
310 
311         if(dc.GetSafeHdc() != NULL)
312         {
313             memDC.CreateCompatibleDC(&dc) ;//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
314             memBitmap.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;//建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
315             oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ;//只有选入了位图的设备描述表才有地方绘图,画到指定的位图上
316 
317             if (memDC.GetSafeHdc() != NULL)
318             {
319                 // first drop the grid on the memory dc
320                 memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, 
321                          &m_dcGrid, 0, 0, SRCCOPY) ;
322              // now add the plot on top as a "pattern" via SRCPAINT.
323              // works well with dark background and a light plot
324                 memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, 
325                            &m_dcPlot, 0, 0, SRCPAINT) ;  //SRCPAINT
326              // finally send the result to the display
327                 dc.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, 
328                           &memDC, 0, 0, SRCCOPY) ;
329             }
330 
331             memDC.SelectObject(oldBitmap) ;
332         }
333     }
334 }
335 //将当前数据点绘制到plotBitmap上    
336 void CDrawView::DrawPoint()
337 { 
338     double currX, prevX, currY, prevY ;
339 
340     CPen *oldPen ;
341     CRect rectCleanUp ;
342 
343     if (m_dcPlot.GetSafeHdc() != NULL)
344     {
345 
346         oldPen = m_dcPlot.SelectObject(&m_penPlot) ;
347      // 移到由prevX和prevY指定的前一个位置
348         prevX = m_rectPlot.left +  m_dPreviousPosition.x * m_dHorizontalFactor;
349         prevY = m_rectPlot.bottom - 
350               (long)((m_dPreviousPosition.y - m_dYLowerLimit) * m_dVerticalFactor);
351         m_dcPlot.MoveTo (prevX, prevY);
352 
353      // 画到当前点的位置
354         currX = m_rectPlot.left + m_dCurrentPosition.x * m_dHorizontalFactor;
355         currY = m_rectPlot.bottom - 
356             (long)((m_dCurrentPosition.y - m_dYLowerLimit) * m_dVerticalFactor);
357         m_dcPlot.LineTo (currX, currY);
358 
359     // restore the pen 
360         m_dcPlot.SelectObject(oldPen) ;
361     // store the current point for connection to the next point
362         m_dPreviousPosition.x = m_dCurrentPosition.x ;
363         m_dPreviousPosition.y = m_dCurrentPosition.y;
364   }
365 
366 } // end DrawPoint
367 void CDrawView::OnPaint()
368 {
369         if(m_dcGrid.GetSafeHdc() != NULL)
370         {
371             m_dcGrid.DeleteDC();
372             m_pBitmapGrid.DeleteObject();
373         }
374         if(m_dcPlot.GetSafeHdc() != NULL)
375         {
376             m_dcPlot.DeleteDC();
377             m_pBitmapPlot.DeleteObject();
378         }
379             
380     InvalidateCtrl();
381 
382     double pointX,pointY;
383     CPoint tempPoint;
384     CPen *oldPen1 ;
385     //dataList1.RemoveAll();
386     if(dataList.GetCount() > 1)
387     {
388         //绘图区域大小已经改变,需要重绘
389         if(m_dcPlot.GetSafeHdc() != NULL )
390         {
391             oldPen1 = m_dcPlot.SelectObject(&m_penPlot) ;
392             POSITION pos1 = dataList.GetHeadPosition();
393             
394             tempPoint = dataList.GetNext(pos1);
395             pointX = m_rectPlot.left + tempPoint.x * m_dHorizontalFactor;
396             pointY = m_rectPlot.bottom - 
397                 (long)((tempPoint.y - m_dYLowerLimit) * m_dVerticalFactor);
398             m_dcPlot.MoveTo(pointX,pointY);
399             CString str;
400             str.Format(_T("long is %d"),dataList.GetCount());
401             //TRACE(str);
402             for(int i = 1; i < dataList.GetCount();i++ )
403             {
404                 tempPoint = dataList.GetNext(pos1);
405                 pointX = m_rectPlot.left + tempPoint.x * m_dHorizontalFactor;
406                 pointY = m_rectPlot.bottom - 
407                 (long)((tempPoint.y - m_dYLowerLimit) * m_dVerticalFactor);
408                 m_dcPlot.LineTo(pointX,pointY);
409                 m_dcPlot.MoveTo(pointX,pointY);
410             }
411             m_dcPlot.SelectObject(oldPen1);
412         }
413     }
414 
415 
416     if(m_nClientHeight != 0)
417     {
418         CPaintDC dc(this) ;  // device context for painting
419     
420         CDC memDC ;            //定义一个内存设备描述表对象(即后备缓冲区)
421         CBitmap memBitmap ;    //定义一个位图对象
422         CBitmap* oldBitmap ; // bitmap originally found in CMemDC
423 
424         memDC.CreateCompatibleDC(&dc) ;//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
425         memBitmap.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;//建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
426         oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ;//只有选入了位图的设备描述表才有地方绘图,画到指定的位图上
427     
428         if (memDC.GetSafeHdc() != NULL)
429         {
430             
431              //first drop the grid on the memory dc
432             memDC.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, 
433                  &m_dcGrid, 0, 0, SRCCOPY) ;
434              // now add the plot on top as a "pattern" via SRCPAINT.
435          // works well with dark background and a light plot
436     
437             memDC.BitBlt(0, 0, m_nPlotWidth, m_nPlotHeight, 
438                    &m_dcPlot, 0, 0, SRCPAINT) ;  //SRCPAINT
439           //finally send the result to the display    
440             dc.BitBlt(0, 0, m_nClientWidth, m_nClientHeight, 
441                   &memDC, 0, 0, SRCCOPY) ;
442             
443         }
444 
445         memDC.SelectObject(oldBitmap) ;
446         memDC.DeleteDC();
447         memBitmap.DeleteObject();
448     }    
449 }
450 
451 
452 void CDrawView::Reset()
453 {
454   InvalidateCtrl() ;
455 }        
456 
457 
458 BOOL CDrawView::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
459 {
460     // TODO: 在此添加专用代码和/或调用基类
461     BOOL result;
462     static CString className = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW);//注册窗口类,返回值包含创建的窗口类的信息
463     result = CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, 
464                           className, NULL, dwStyle, 
465                           rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
466                           pParentWnd->GetSafeHwnd(), (HMENU)nID) ;
467     m_dPreviousPosition.x = 0;
468     m_dPreviousPosition.y = 0;
469 
470     m_dCurrentPosition.x = 0;
471     m_dCurrentPosition.y = 0;
472     if (result != 0)
473         // InvalidateCtrl() ;
474     
475     return result ;
476 }
477 
478 
479 void CDrawView::OnSize(UINT nType, int cx, int cy)
480 {
481     CWnd::OnSize(nType, cx, cy);
482 
483     GetClientRect(&m_rectClient) ;
484     // set some member variables to avoid multiple function calls
485     m_nClientHeight = m_rectClient.Height() ;
486     m_nClientWidth  = m_rectClient.Width() ;
487     // the "left" coordinate and "width" will be modified in 
488     // InvalidateCtrl to be based on the width of the y axis scaling
489     m_rectPlot.left   = 20 ;  
490     m_rectPlot.top    = 25;
491     m_rectPlot.right  = m_rectClient.right-10 ;
492     m_rectPlot.bottom = m_rectClient.bottom-25 ;
493 
494     // set some member variables to avoid multiple function calls
495     m_nPlotHeight = m_rectPlot.Height() ;
496     m_nPlotWidth  = m_rectPlot.Width() ;
497 
498     // set the scaling factor for now, this can be adjusted 
499     // in the SetRange functions
500     m_dVerticalFactor = (double)m_nPlotHeight / m_dYRange ; 
501     m_dHorizontalFactor = (double)m_nClientWidth / m_dXRange /400.0 /** (m_updateRate * 400)*/;
502     
503 }
504 void CDrawView::setUpdateRate(double updateRate)
505 {
506     m_updateRate = updateRate;
507 }
View Code

 

以上是关于MFC--根据串口采集的数据借助GDI绘制曲线的主要内容,如果未能解决你的问题,请参考以下文章

串口屏开发之曲线控件的使用总结——如何将实时采集的数据连成曲线显示在屏幕上

串口屏开发之曲线控件的使用总结——如何将实时采集的数据连成曲线显示在屏幕上

MFC-GDI和GDI+

MFC--串口编程---WIN API的方式将串扣操作封装在线程类中

MFC GDI绘图基础

怎么在mfc中画曲线