MultiColorPlotCtrl.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. ////////////////////////////////////////////////////////////////////////
  2. //文件名 :MULTICOLORPLOT.CPP
  3. //控件说明:实时曲线显示功能控件,提供LINE和BAR两种曲线显示功能
  4. //作者: 戚高
  5. //完成日期:2007-01-17
  6. //版权 :可以自由使用代码
  7. ///////////////////////////////////////////////////////////////////////
  8. #include "stdafx.h"
  9. #include "MultiColorPlotCtrl.h"
  10. #include ".\multicolorplotctrl.h"
  11. #ifdef _DEBUG
  12. #define new DEBUG_NEW
  13. #undef THIS_FILE
  14. static char THIS_FILE[] = __FILE__;
  15. #endif
  16. /////////////////////////////////////////////////////////////////////////////
  17. // CMultiColorPlotCtrl
  18. CMultiColorPlotCtrl::CMultiColorPlotCtrl()
  19. : nPlotType(BAR)
  20. , nGridResolutionX(10)
  21. , nGridResolutionY(10)
  22. , nGridScrollSpeedX(-2)
  23. , nGridScrollSpeedY(0)
  24. , nPlotGranulatrity(2)
  25. , nGridLineWidth(1)
  26. , m_clrDarkBack(RGB(0,0,75))
  27. , m_clrDarkLine(RGB(32,64,32))
  28. , nPlotData(0)
  29. , pfData(NULL)
  30. , fLow(0.0)
  31. , fHigh(100.0)
  32. , fScaleY(1.0)
  33. , m_clrCyanData(RGB(0,255,255))
  34. , nGridStarPosX(0)
  35. , nGridStarPosY(0)
  36. , bLock(true)
  37. , m_clrAxisScaleY(RGB(0,255,255))
  38. , nShowFormatDataText(0)
  39. , m_clrLinePen(RGB(0,255,0))
  40. , nLineWidth(1)
  41. {
  42. // 关键代码
  43. // 初始化关键代码的 C_S 结构
  44. InitializeCriticalSection ( & g_cs ) ;
  45. // 初始化标题
  46. _stprintf ( szTitls , _TEXT ( "%s" ) , _TEXT ( "" ) ) ;
  47. // 初始化单位
  48. _stprintf ( szUints , _TEXT ( "%s" ) , _TEXT ( "" ) ) ;
  49. }
  50. CMultiColorPlotCtrl::~CMultiColorPlotCtrl()
  51. {
  52. if ( pfData )
  53. {
  54. delete [] pfData ;
  55. }
  56. // 释放关键代码
  57. DeleteCriticalSection ( & g_cs ) ;
  58. }
  59. BEGIN_MESSAGE_MAP(CMultiColorPlotCtrl, CStatic)
  60. //{{AFX_MSG_MAP(CMultiColorPlotCtrl)
  61. ON_WM_PAINT()
  62. //}}AFX_MSG_MAP
  63. ON_WM_ERASEBKGND()
  64. ON_WM_TIMER()
  65. END_MESSAGE_MAP()
  66. /////////////////////////////////////////////////////////////////////////////
  67. // CMultiColorPlotCtrl message handlers
  68. void CMultiColorPlotCtrl::OnPaint()
  69. {
  70. CPaintDC dc(this); // device context for painting
  71. // 获得控件区域
  72. GetClientRect (&m_rectCtrl);
  73. // 创建内存 DC
  74. CMemDC *pMemDC = new CMemDC(&dc, &m_rectCtrl);
  75. CPoint orgBrushOrigin = pMemDC->GetBrushOrg () ;
  76. if(m_dcBackground.GetSafeHdc() == NULL || m_pBitmapBackground.m_hObject == NULL)
  77. {
  78. m_dcBackground.CreateCompatibleDC(&dc);
  79. m_pBitmapBackground.CreateCompatibleBitmap(&dc, m_rectCtrl.Width(),m_rectCtrl.Height()) ;
  80. m_pBitmapOldBackground = m_dcBackground.SelectObject(&m_pBitmapBackground) ;
  81. InitColorPlot(&m_dcBackground);
  82. }
  83. pMemDC->BitBlt(0, 0, m_rectCtrl.Width(), m_rectCtrl.Height(),
  84. &m_dcBackground, 0, 0, SRCCOPY) ;
  85. //画曲线背景和网格
  86. DrawBackGroundGrid(pMemDC);
  87. //画曲线数据
  88. DrawValue(pMemDC);
  89. //画曲线Y刻度
  90. DrawAxisScaleYValue(pMemDC);
  91. pMemDC->SetBrushOrg ( orgBrushOrigin.x , orgBrushOrigin.y ) ;
  92. delete pMemDC ;
  93. }
  94. // 设置画线的类型
  95. void CMultiColorPlotCtrl::SetPlotType(int nType)
  96. {
  97. nPlotType = nType ;
  98. }
  99. // 数据点面积大小(即:一个数据点占据的像素数)
  100. BOOL CMultiColorPlotCtrl::SetPlotGranulatrity(int nPlotGrltiy)
  101. {
  102. nPlotGranulatrity = nPlotGrltiy ;
  103. nPlotData = m_Size.cx / nPlotGranulatrity ;
  104. pfData = new float [nPlotData] ;
  105. if ( pfData )
  106. {
  107. // 初始化数据为 0
  108. ZeroMemory ( pfData , sizeof ( pfData ) * nPlotData ) ;
  109. return TRUE ;
  110. }
  111. return FALSE ;
  112. }
  113. // 前景色
  114. void CMultiColorPlotCtrl::SetGridLineClr(COLORREF clr)
  115. {
  116. m_clrDarkLine = clr ;
  117. m_GridPen.CreatePen ( PS_SOLID , nGridLineWidth , m_clrDarkLine ) ;
  118. m_clrDarkLine = clr ;
  119. }
  120. // 数据范围
  121. void CMultiColorPlotCtrl::SetRang(float fL, float fH)
  122. {
  123. fLow = fL ;
  124. fHigh = fH ;
  125. }
  126. // 创建画笔
  127. void CMultiColorPlotCtrl::SetLinePen(int nWidth, COLORREF clr)
  128. {
  129. nGridLineWidth = nWidth ;
  130. m_clrDarkLine = clr ;
  131. m_GridPen.CreatePen ( PS_SOLID , nGridLineWidth , m_clrDarkLine ) ;
  132. }
  133. // Y轴刻度颜色
  134. void CMultiColorPlotCtrl::SetAxisScaleClrY(COLORREF clr)
  135. {
  136. m_clrAxisScaleY = clr ;
  137. }
  138. // 标题
  139. void CMultiColorPlotCtrl::SetTitle(LPCTSTR pctTitle)
  140. {
  141. _stprintf ( szTitls , _TEXT ( "%s" ) , pctTitle ) ;
  142. }
  143. // 数据单位例:SetUnit( _TEXT ( "(k/sec)" ) ) ;
  144. void CMultiColorPlotCtrl::SetUnit(LPCTSTR pctUint)
  145. {
  146. _stprintf ( szUints , _TEXT ( "%s" ) , pctUint ) ;
  147. }
  148. // 是否显示数据标题、颜色、单位
  149. /*
  150. nShow = 0 ; 不显示任何文本
  151. nShow = 1 ; 仅仅显示标题
  152. nShow = 2 ; 仅仅显示标题和流量总计
  153. nShow = 3 ; 显示标题和最小值
  154. nShow = 4 ; 显示标题、最小值和中值
  155. */
  156. void CMultiColorPlotCtrl::ShowTitle(int nShow)
  157. {
  158. nShowFormatDataText = nShow ;
  159. }
  160. // BAR 颜色
  161. // clrUp -------- 顶部颜色
  162. // clrDown -------- 底部颜色
  163. // bfRfastness -------- 红色分量是否固定不变 false ---- 渐变
  164. // bfGfastness -------- 红色分量是否固定不变 false ---- 渐变
  165. // bfBfastness -------- 红色分量是否固定不变 false ---- 渐变
  166. void CMultiColorPlotCtrl::SetBarColor(COLORREF clrUp, COLORREF clrDown, bool bfRfastness, bool bfGfastness, bool bfBfastness)
  167. {
  168. }
  169. // 曲线颜色
  170. void CMultiColorPlotCtrl::SetLineColorWidth(COLORREF clrLine, int nWidth)
  171. {
  172. nLineWidth = nWidth ;
  173. m_clrLinePen = clrLine ;
  174. }
  175. void CMultiColorPlotCtrl::PreSubclassWindow()
  176. {
  177. // TODO: Add your specialized code here and/or call the base class
  178. // 相应通告消息
  179. ModifyStyle( 0 , SS_NOTIFY ) ;
  180. GetClientRect ( & m_rectCtrl ) ;
  181. // 得到该控件的宽和高
  182. m_Size.cx = m_rectCtrl.right - m_rectCtrl.left ;
  183. m_Size.cy = m_rectCtrl.bottom - m_rectCtrl.top ;
  184. // 计算控件可容纳可见的数据点数
  185. nPlotData = m_Size.cx / nPlotGranulatrity ;
  186. // 设置控件上显示的文字的字体和大小
  187. m_SmallFont.CreateFont( -11 , 0 , 0 , 0 , FW_THIN , false , false , false , DEFAULT_CHARSET ,
  188. OUT_DEFAULT_PRECIS , CLIP_DEFAULT_PRECIS , DEFAULT_QUALITY , VARIABLE_PITCH , _TEXT( "Times New Roman" ) ) ;
  189. // 给实际数据分配内存
  190. pfData = new float [ nPlotData ] ;
  191. if ( pfData )
  192. {
  193. // 初始化数据为 0
  194. ZeroMemory ( pfData , sizeof ( pfData ) * nPlotData ) ;
  195. m_GridPen.CreatePen ( PS_SOLID , nGridLineWidth , m_clrDarkLine ) ;
  196. CRgn m_Rgn ;
  197. m_Rgn.CreateRoundRectRgn ( 0 , 0 , m_Size.cx , m_Size.cy , 10 , 10 ) ;
  198. SetWindowRgn ( ( HRGN ) m_Rgn , true ) ;
  199. SetTimer ( GRID_TIMER , GRID_UPDATE_SPEED , NULL ) ;
  200. }
  201. CStatic::PreSubclassWindow();
  202. }
  203. BOOL CMultiColorPlotCtrl::OnEraseBkgnd(CDC* pDC)
  204. {
  205. // TODO: 在此添加消息处理程序代码和/或调用默认值
  206. return TRUE;
  207. }
  208. void CMultiColorPlotCtrl::ReconstructControl(void)
  209. {
  210. }
  211. void CMultiColorPlotCtrl::InitColorPlot(CDC *pDC)
  212. {
  213. // 根据不同的曲线分别绘制
  214. if ( nPlotType == BAR )
  215. {
  216. double factor = 255.0 / ( float ) m_Size.cy ;
  217. BYTE r , g , b ;
  218. for ( int x = 0 ; x < m_Size.cy ; x ++ )
  219. {
  220. g = ( BYTE ) ( 255 - factor * x ) ;
  221. r = ( BYTE ) ( factor * x ) ;
  222. b = ( BYTE ) 64 ;
  223. pDC->SetPixelV ( 0 , x , RGB ( r , g , b ) ) ;
  224. pDC->SetPixelV ( 1 , x , RGB ( r , g , b ) ) ;
  225. }
  226. }
  227. else if ( nPlotType == LINE )
  228. {
  229. }
  230. else
  231. {
  232. }
  233. pDC->SelectObject ( m_pBitmapOldBackground ) ;
  234. // 生成位图画刷
  235. m_clrBrush.CreatePatternBrush ( & m_pBitmapBackground ) ;
  236. }
  237. //绘制网格和背景
  238. void CMultiColorPlotCtrl::DrawBackGroundGrid(CDC * pDC)
  239. {
  240. // 填充背景色
  241. pDC->FillSolidRect ( & m_rectCtrl , m_clrDarkBack ) ;
  242. // 画网格
  243. int nGridLinesX = m_Size.cx / nGridResolutionX ;
  244. int nGridLinesY = m_Size.cy / nGridResolutionY ;
  245. // 选择画笔
  246. CPen * pOldPen = pDC->SelectObject ( & m_GridPen ) ;
  247. // 创建垂直线
  248. for ( int x = 0 ; x <= nGridLinesX ; x ++ )
  249. {
  250. pDC->MoveTo ( x * nGridResolutionX + nGridStarPosX , 0 );
  251. pDC->LineTo ( x * nGridResolutionX + nGridStarPosX , m_Size.cy );
  252. }
  253. // 添加水平线
  254. for ( int y = 0 ; y <= nGridLinesY ; y ++ )
  255. {
  256. pDC->MoveTo ( 0 , nGridStarPosY + m_Size.cy - y * nGridResolutionY - 2 ) ;
  257. pDC->LineTo ( m_Size.cx , nGridStarPosY + m_Size.cy - y * nGridResolutionY - 2 ) ;
  258. }
  259. // 控制网格正确移动
  260. nGridStarPosX += nGridScrollSpeedX ;
  261. nGridStarPosY += nGridScrollSpeedY ;
  262. if ( nGridStarPosX < 0 ) nGridStarPosX = nGridResolutionX ;
  263. if ( nGridStarPosX > nGridResolutionX ) nGridStarPosX = 0 ;
  264. if ( nGridStarPosY < 0 ) nGridStarPosY = nGridResolutionY ;
  265. if ( nGridStarPosY > nGridResolutionY ) nGridStarPosY = 0 ;
  266. // 还原网格画笔
  267. pDC->SelectObject ( pOldPen ) ;
  268. }
  269. void CMultiColorPlotCtrl::DrawValue(CDC * pDC)
  270. {
  271. float fx , fy ;
  272. // 用关键代码同步和SetData
  273. EnterCriticalSection ( & g_cs ) ;
  274. if ( nPlotType == BAR )
  275. {
  276. RECT rFill ;
  277. for ( int nData = 0 ; nData < nPlotData ; nData ++ )
  278. {
  279. fx = ( float ) ( m_rectCtrl.left + nData * nPlotGranulatrity ) ;
  280. fy = ( float ) fabs ( ( float ) ( m_rectCtrl.bottom - ( ( ( ( pfData[nData] - fLow ) / ( fHigh - fLow ) ) * m_Size.cy ) ) ) ) ;
  281. rFill.bottom = ( LONG ) m_rectCtrl.bottom ;
  282. rFill.top = ( LONG ) fy ;
  283. rFill.left = ( LONG ) fx ;
  284. rFill.right = ( LONG ) ( fx + nPlotGranulatrity ) ;
  285. pDC->SetBrushOrg ( ( int ) fx , m_rectCtrl.bottom ) ;
  286. // 用初始化画刷时生成的渐变位图画刷填充矩形
  287. pDC->FillRect ( & rFill , & m_clrBrush ) ;
  288. // 画数据点处的颜色
  289. pDC->SetPixelV ( ( int ) fx , ( int ) fy , m_clrCyanData ) ;
  290. }
  291. }
  292. else if ( nPlotType == LINE )
  293. {
  294. CPoint * g_DataPoint = new CPoint [nPlotData] ;
  295. // 创建曲线画笔
  296. CPen m_Pen ;
  297. m_Pen.CreatePen ( PS_SOLID , nLineWidth , m_clrLinePen ) ;
  298. CPen * m_pOldPen = pDC->SelectObject ( & m_Pen ) ;
  299. for ( int nData = 0 ; nData < nPlotData ; nData ++ )
  300. {
  301. g_DataPoint[nData].x = ( LONG ) ( m_rectCtrl.left + nData * nPlotGranulatrity ) ;
  302. g_DataPoint[nData].y = ( LONG ) fabs ( ( float ) ( m_rectCtrl.bottom - ( ( ( ( pfData[nData] - fLow ) / ( fHigh - fLow ) ) * m_Size.cy ) ) ) ) ;
  303. }
  304. pDC->Polyline ( g_DataPoint , nPlotData ) ;
  305. pDC->SelectObject ( m_pOldPen ) ;
  306. delete [] g_DataPoint ;
  307. }
  308. else
  309. {
  310. }
  311. }
  312. void CMultiColorPlotCtrl::DrawAxisScaleYValue(CDC * pDC)
  313. {
  314. CFont * pOldFont ;
  315. // 绘制Y轴刻度
  316. TCHAR szAxisScaleYMax [MAX_PATH * sizeof ( TCHAR ) + 1] ;
  317. TCHAR szAxisScaleYMin [MAX_PATH * sizeof ( TCHAR ) + 1] ;
  318. TCHAR szAxisScaleY [MAX_PATH * sizeof ( TCHAR ) + 1] ;
  319. ZeroMemory ( & szAxisScaleYMax , sizeof ( szAxisScaleYMax ) ) ;
  320. ZeroMemory ( & szAxisScaleYMin , sizeof ( szAxisScaleYMin ) ) ;
  321. ZeroMemory ( & szAxisScaleY , sizeof ( szAxisScaleY ) ) ;
  322. COLORREF clrText = pDC->GetTextColor () ;
  323. int nBkMode = pDC->GetBkMode () ;
  324. pDC->SetTextColor ( m_clrAxisScaleY ) ;
  325. pDC->SetBkMode ( TRANSPARENT ) ;
  326. pOldFont = pDC->SelectObject ( & m_SmallFont ) ;
  327. // 如果要求现实Y轴刻度数字
  328. switch ( nShowFormatDataText )
  329. {
  330. case 0 : // 不显示
  331. {
  332. }
  333. break ;
  334. case 1 : // 仅显示标题
  335. {
  336. _stprintf ( szAxisScaleYMax , _TEXT ( "%s" ) , szTitls ) ;
  337. pDC->TextOut ( 0 , 0 , szAxisScaleYMax ) ;
  338. }
  339. break ;
  340. case 2 : // 显示标题和流量比例
  341. {
  342. _stprintf ( szAxisScaleYMax , _TEXT ( "%s %8.1f %s / %8.1f" ) , szTitls , pfData [ nPlotData - 1 ] , szUints , fHigh ) ;
  343. pDC->TextOut ( 0 , 0 , szAxisScaleYMax ) ;
  344. }
  345. break ;
  346. case 3 : // 显示最大最小值
  347. {
  348. // 格式化最大值和标题及单位
  349. _stprintf ( szAxisScaleYMax , _TEXT ( "%s %8.1f %s / %8.1f" ) , szTitls , pfData [ nPlotData - 1 ] , szUints , fHigh ) ;
  350. // 格式化最小值
  351. _stprintf ( szAxisScaleYMin , _TEXT ( "%8.1f" ) , fLow ) ;
  352. pDC->TextOut ( 0 , 0 , szAxisScaleYMax ) ;
  353. pDC->TextOut ( 0 , m_Size.cy - 10 , szAxisScaleYMin ) ;
  354. }
  355. break ;
  356. case 4 : // 显示全部
  357. {
  358. // 格式化最大值和标题及单位
  359. _stprintf ( szAxisScaleYMax , _TEXT ( "%s %8.1f %s / %8.1f" ) , szTitls , pfData [ nPlotData - 1 ] , szUints , fHigh ) ;
  360. // 格式化最小值
  361. _stprintf ( szAxisScaleYMin , _TEXT ( "%8.1f" ) , fLow ) ;
  362. // 格式化中值
  363. _stprintf ( szAxisScaleY , _TEXT ( "%8.1f" ) , ( ( fHigh - fLow ) / 2.0 + fLow ) ) ;
  364. // 绘制Y轴刻度
  365. pDC->TextOut ( 0 , 0 , szAxisScaleYMax ) ;
  366. pDC->TextOut ( 0 , m_Size.cy - 10 , szAxisScaleYMin ) ;
  367. pDC->TextOut ( 0 , m_Size.cy / 2 , szAxisScaleY ) ;
  368. } break ;
  369. }
  370. pDC->SetTextColor ( clrText ) ;
  371. pDC->SetBkMode ( nBkMode ) ;
  372. pDC->SelectObject ( pOldFont ) ;
  373. // 离开关键代码
  374. LeaveCriticalSection ( & g_cs ) ;
  375. }
  376. void CMultiColorPlotCtrl::OnTimer(UINT nIDEvent)
  377. {
  378. // TODO: 在此添加消息处理程序代码和/或调用默认值
  379. switch ( nIDEvent )
  380. {
  381. case GRID_TIMER :
  382. {
  383. }
  384. break ;
  385. }
  386. Invalidate ( false ) ;
  387. CStatic::OnTimer(nIDEvent);
  388. }
  389. // 设置网格间距
  390. void CMultiColorPlotCtrl::SetGridResolutionX(int nGridReluX)
  391. {
  392. nGridResolutionX = nGridReluX ;
  393. }
  394. // 设置网格间距
  395. void CMultiColorPlotCtrl::SetGridResolutionY(int nGridReluY)
  396. {
  397. nGridResolutionY = nGridReluY ;
  398. }
  399. // 设置网格滚动速度,正值为从左向右滚动,0不动
  400. void CMultiColorPlotCtrl::SetGridScrollSpeedX(int nSpeedX)
  401. {
  402. nGridScrollSpeedX = nSpeedX ;
  403. }
  404. // 正值为从上到下滚动,0不动
  405. void CMultiColorPlotCtrl::SetGridScrollSpeedY(int nSpeedY)
  406. {
  407. nGridScrollSpeedY = nSpeedY ;
  408. }
  409. // 网格线宽度
  410. void CMultiColorPlotCtrl::SetGridLineWidth(int nWidth)
  411. {
  412. nGridLineWidth = nWidth ;
  413. }
  414. // 背景色
  415. void CMultiColorPlotCtrl::SetGridBackClr(COLORREF clr)
  416. {
  417. m_clrDarkBack = clr ;
  418. }
  419. // // 锁定数据显示范围
  420. void CMultiColorPlotCtrl::LockRang(bool bfLock)
  421. {
  422. bLock = bfLock ;
  423. }
  424. // 锁定数据显示范围
  425. void CMultiColorPlotCtrl::LockRang(float fMin, float fMax)
  426. {
  427. fLow = fMin ;
  428. fHigh = fMax ;
  429. LockRang ( true ) ;
  430. }
  431. // 设置数据
  432. void CMultiColorPlotCtrl::SetData(float fData)
  433. {
  434. // 用关键代码同步
  435. EnterCriticalSection ( & g_cs ) ;
  436. for ( int n = 0 ; n < nPlotData - 1 ; n ++ )
  437. {
  438. pfData [ n ] = pfData [ n + 1 ] ;
  439. }
  440. pfData [ nPlotData - 1 ] = fData ;
  441. if ( bLock ) // 锁定比例范围
  442. {
  443. }
  444. else
  445. {
  446. // 保存最小值
  447. if ( fLow > fData )
  448. {
  449. fLow = fData ;
  450. }
  451. // 保存最大值
  452. if ( fHigh < fData )
  453. {
  454. fHigh = fData ;
  455. }
  456. }
  457. // 离开关键代码
  458. LeaveCriticalSection ( & g_cs ) ;
  459. }
  460. // 曲线颜色
  461. void CMultiColorPlotCtrl::SetLineColor(COLORREF clrLine)
  462. {
  463. m_clrLinePen = clrLine ;
  464. }
  465. void CMultiColorPlotCtrl::SetLineWidth(int nWidth)
  466. {
  467. nLineWidth = nWidth ;
  468. }
  469. const COLORREF CMultiColorPlotCtrl::GetLineColor(void)
  470. {
  471. return m_clrLinePen ;
  472. }
  473. const int CMultiColorPlotCtrl::GetLineWidth(void)
  474. {
  475. return nLineWidth ;
  476. }