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 };
该类的实现文件内容:
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 }