图表曲线Teechart——采用Cdib类和内存映射文件加快TChart控件画图速度的实现方法

转自:http://topic.csdn.net/t/20030601/16/1862242.html

 

 

1 引言  
  在最近的编程实践中发现,虽然TeeChart   ActiveX   Pro5.0控件能够很方便的实现画图线等操作【1】,但是对于大数据量的文件读取和显示,例如一个64M数据文件的显示,速度将非常的慢。本文描述了一种采用CDib类【2】作为“画布”,将所有的画图操作在此CDib对象中完成后,再映射到TeeChart   ActiveX   Pro5.0控件的Canvas上完成画图操作。对比试验证明,此方法可使画图操作获得上百倍速度的提高。(CDib类是David   Kruglinski在《Inside   Visual   C++》一书中提供的。它是免费使用和发布的,在使用时,应该提到作者以示尊重。)  
   
  2 实现步骤  
  2.1 在CFormView中声明私有对象m_Dib  
  使用MFC   AppWizard   创建一个新的SDI程序CMyApp,选择View的类型为CFormView。在CFormView中插入TeeChart   ActiveX   Pro   5.0控件,并在CFormView类中声明私有变量m_Dib。  
  //CMyView.h  
  private:  
  CDib   m_Dib;  
   
  2.2 在CMyDoc中声明并使用内存映射文件  
  在CMyDoc中声明内存映射文件  
  //CMyDoc.h  
  public:  
  HANDLE   m_hMapFile; //内存映射文件的HANDLE  
  LPVOID   m_lpMapFile; //指向内存映射文件数据的指针,可用于  
  //访问文件  
  并在CMyDoc的Serialize函数中加入以下代码:  
   
  //以下代码实现用户打开数据文件时,为所需打开的文件进行内存映射;  
  void   CMyDoc::Serialize(CArchive&   ar)  
  {  
  if   (ar.IsStoring())  
  {  
  //   TODO:   add   storing   code   here  
  }  
  else  
  {  
  //   TODO:   add   loading   code   here  
  //首先检查m_lpMapFile和m_hMapFile是否为空,如果是,首先取消原有  
  //的映射;  
  if   (m_lpMapFile!=NULL)   {  
  UnmapViewOfFile(m_lpMapFile);  
  }  
  if   (m_hMapFile!=NULL)   {  
  CloseHandle(m_hMapFile);  
  }  
  //创建内存映射文件HANDLE;  
  m_hMapFile=CreateFileMapping((HANDLE)ar.GetFile()->m_hFile,  
  NULL,  
  PAGE_READONLY,  
  0,  
  ar.GetFile()->GetLength(),  
  "Test");  
  //创建内存映射文件的数据指针,可用于访问文件内的数据;  
  m_lpMapFile=MapViewOfFile(m_hMapFile,  
  FILE_MAP_READ,  
  0,  
  0,  
  ar.GetFile()->GetLength());  
  }  
  }  
   
  2.3 程序关闭或者文件关闭时,在CMyDoc的析构函数中,确保取消数据文件的内存映射;  
  CMyDoc::~   CMyDoc   ()  
  {  
  //关闭内存映射文件的HANDLE  
  if   (m_hMapFile!=NULL)   {  
  CloseHandle(m_hMapFile);  
  }  
  //取消对内存映射文件视图的映射;  
  if   (m_lpMapFile!=NULL)   {  
  UnmapViewOfFile(m_lpMapFile);  
  }  
  }  
   
  2.4 加上菜单Test,在它的事件响应函数中加入以下对CDib画图的代码  
  void   CMyView::OnTest()    
  {  
  //   TODO:   Add   your   command   handler   code   here  
  //获取文件指针pDoc;  
  CMyDoc*   pDoc=GetDocument();  
  //利用pDoc->m_lpMapFile映射文件视图数据指针,访问数据文件;  
  //m_lpMapFile的类型是LPVOID,需要对它进行类型强制转换为所需类型  
  int*   pMapFile=(int*)pDoc->m_lpMapFile;  
  //以下是特定的数据文件访问代码,用户可根据自己需要进行访问;  
  int   nChlNum=*(   pMapFile);  
  int   nLayerCount=(nChlNum-6);  
  int   nChlIndex=23;  
  int   nChlLen=*(   pMapFile   +1+nChlIndex);  
  int   nFrmNums=*(   pMapFile   +1+nChlNum);  
  int   nHeadOffset=(nChlNum+2)*sizeof(int);  
  int   nFrmCount=0;  
  for(int   i=0;i<nChlNum;i++)  
  nFrmCount=nFrmCount+*((int*)pDoc->m_lpMapFile+i+1);  
  int   nFrmOffset=0;  
  for(i=0;i<nChlIndex;i++)  
  nFrmOffset=nFrmOffset+*((int*)pDoc->m_lpMapFile+i+1);  
   
  //Create函数是我参考构造函数m_Dib::m_Dib(CSize   size,int   nBitCount)修改  
  //得来的,请参考demo项目;它可以方便清空m_Dib内存,重新设置m_Dib  
  //的大小  
  m_Dib.Create(CSize(nChlLen,nFrmNums),24);  
  //引用Chart控件的Canvas,  
  CDC   DC;  
  GETCHART(pChart)  
  DC.Attach((HDC)pChart->GetCanvas().GetHandleDC());  
  //把m_Dib与DC关联起来,并为m_Dib分配内存;  
  m_Dib.CreateSection(&DC);  
   
  //CDib的方便之处在于可以使用它的m_lpImage指针访问图中的每个点,由于  
  //它本身也采用了Windows的画图优化算法,所以速度更快;  
  BYTE*   pDibByte=m_Dib.m_lpImage;  
  //这个nOffset是m_Dib行与行之间m_lpImage必须加上的偏移量,否则访问的  
  //位置不对  
  int   nOffset=nChlLen%4;  
   
  BYTE   val;  
  for   (i=0;   i<nFrmNums;   i++) //每一行  
  {  
  for   (int   j=0;   j<nChlLen;   j++) //每一列  
  {  
  val=*((BYTE*)pDoc->m_lpMapFile   +   nHeadOffset   +   nFrmOffset+   i*nFrmCount   +   j);  
  *(pDibByte++)=val; //蓝色值Blue;  
  *(pDibByte++)=val; //绿色值Green  
  *(pDibByte++)=val; //红色值Red  
  }  
  pDibByte+=Offset; //行与行之间必须加上的偏移量;  
   
  }  
  //在使用完DC后,必须解除引用;  
  DC.Detach();  
  }  
   
  2.5 在TChart控件的OnBeforeDrawSeriesChart()的事件响应函数中将m_Dib画到Chart的Canvas上  
   
  void   CMyView::OnOnBeforeDrawSeriesChart()    
  {  
  //   TODO:   Add   your   control   notification   handler   code   here  
  CDC   DC;  
  CTChart*   pChart=(CTChart*)GetDlgItem(IDC_CHART);  
  //引用Chart控件的Canvas;  
  DC.Attach((HDC)pChart->GetCanvas().GetHandleDC());  
  //获取Chart控件的左上角位置;  
  m_ptOrigin=CPoint(pChart->GetAxis().GetBottom().CalcXPosValue(pChart->GetSeries(0).GetXValues().GetMinimum()),pChart->GetAxis().GetLeft().CalcYPosValue(pChart->GetSeries(0).GetYValues().GetMinimum()));  
  //获取Chart控件的左右、上下坐标轴所围成的矩形的大小;  
  m_szDraw=CSize(pChart->GetAxis().GetBottom().CalcXPosValue(pChart->GetSeries(0).GetXValues().GetMaximum())-m_ptOrigin.x,pChart->GetAxis().GetLeft().CalcYPosValue(pChart->GetSeries(0).GetYValues().GetMaximum())-m_ptOrigin.y);  
   
  //将m_Dib画到Chart的Canvas上;  
  m_Dib.Draw(&DC,m_ptOrigin,m_szDraw);  
   
  //解除Chart的Canvas的引用;  
  DC.Detach();  
  }  
  3 小结  
  3.1 内存映射文件的使用,方便了数据文件的读取并加快了读取的速度;  
  //创建内存映射文件HANDLE;  
  m_hMapFile=CreateFileMapping((HANDLE)ar.GetFile()->m_hFile,  
  NULL,  
  PAGE_READONLY,  
  0,  
  ar.GetFile()->GetLength(),  
  "Test");  
  //创建内存映射文件的数据指针,可用于访问文件内的数据;  
  m_lpMapFile=MapViewOfFile(m_hMapFile,  
  FILE_MAP_READ,  
  0,  
  0,  
  ar.GetFile()->GetLength());  
   
  //关闭内存映射文件的HANDLE  
  if   (m_hMapFile!=NULL)   {  
  CloseHandle(m_hMapFile);  
  }  
  //取消对内存映射文件视图的映射;  
  if   (m_lpMapFile!=NULL)   {  
  UnmapViewOfFile(m_lpMapFile);  
  }  
   
  3.2 CDib类的使用,很容易的实现了内存DC,加快了画图的速度;  
  //首先设置CDib的大小;    
  m_Dib.Create(CSize(nChlLen,nFrmNums),24);  
   
  //引用Chart控件的Canvas  
  CDC   DC;  
  GETCHART(pChart)  
  DC.Attach((HDC)pChart->GetCanvas().GetHandleDC());  
   
  //把m_Dib与DC关联起来,并为m_Dib分配内存;  
  m_Dib.CreateSection(&DC);  
   
  //进行画图操作  
  ……  
  //将m_Dib画到Chart控件的Canvas上;  
  m_Dib.Draw(&DC,ptOrigin,sizeDraw);  
   
  //记得使用完后要取消DC的引用;  
  DC.Detach();  
   
  3.3 以下是采用以上所述技术所实现的画图功能  
     
   
  参考文献:  
  [1] www.teechart.com  
  [2] 《Inside   Visual   C++》,   Fifth   Edition,   Chapter   Eleven   Bitmaps,   David   Kruglinski   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值