C++制作电压表电流表仪表盘(vs2008)
Meter类
Meter.h
1 #if !defined(AFX_METER_H__D5802279_6502_4453_BE21_58604877AD39__INCLUDED_) 2 #define AFX_METER_H__D5802279_6502_4453_BE21_58604877AD39__INCLUDED_ 3 4 #if _MSC_VER > 1000 5 #pragma once 6 #endif // _MSC_VER > 1000 7 // Meter.h : header file 8 // 9 10 #ifndef ROUND 11 #define ROUND(x) (int)((x) + 0.5 - (double)((x) < 0)) 12 #endif 13 14 #define BOUNDARY_POINTS 200 15 #define TABNUM 6 16 ///////////////////////////////////////////////////////////////////////////// 17 // CMeter window 18 19 class CMeter : public CStatic 20 { 21 // Construction 22 public: 23 CMeter(); 24 25 // Attributes 26 public: 27 28 // Operations 29 public: 30 31 // Overrides 32 // ClassWizard generated virtual function overrides 33 //{{AFX_VIRTUAL(CMeter) 34 protected: 35 //}}AFX_VIRTUAL 36 37 // Implementation 38 public: 39 void SetAngleRange(int nStartAngleDeg, int nEndAngleDeg); 40 int m_nTabNum; 41 void SetSubTicks(int nSubTicks); 42 void SetTicks(int nTicks); 43 void DrawValue(CDC *pDC); 44 void SetColorTick(BOOL bColorTick = FALSE); 45 BOOL m_bColorTick; 46 void DrawNode(CDC *pDC); 47 COLORREF m_colorTable[6]; 48 void SetValueDecimals(int nDecimals); 49 void SetUnits(CString &strUnits); 50 CString m_strUnits; 51 int m_nValueDecimals; 52 void SetScaleDecimals(int nDecimals); 53 void SetRange(double dMin, double dMax); 54 void SetNeedleColor (COLORREF colorNeedle); 55 void UpdateNeedle(double dValue); 56 COLORREF m_colorNeedle; 57 int m_nScaleDecimals; 58 59 double m_dCurrentValue; 60 double m_dMaxValue; 61 double m_dMinValue; 62 63 void DrawNeedle(CDC *pDC); 64 void ReconstructControl(); 65 void DrawMeterBackground(CDC *pDC, CRect &rect); 66 int m_nStartAngleDeg; // 仪表盘圆弧起始角度 67 int m_nEndAngleDeg; // 仪表盘圆弧终止角度 68 int m_nTicks; // 刻度数 69 int m_nSubTicks; // 分刻度数 70 virtual ~CMeter(); 71 72 // Generated message map functions 73 protected: 74 double m_dLeftAngleRad; 75 double m_dRightAngleRad; 76 int m_nCenterRadius; 77 78 CRect m_rectCtrl; // 控件区域 79 CRect m_rectValue; // 显示数值区域 80 CRgn m_rgnBoundary; 81 82 CBitmap *m_pBitmapOldBackground ; 83 CBitmap m_bitmapBackground ; 84 CDC m_dcBackground; 85 86 CPoint m_ptMeterCenter; // 仪表中心 87 CPoint m_pointBoundary[BOUNDARY_POINTS]; // 边界点,用于绘制刻度 88 89 CFont m_font; // 显示文字字体 90 91 COLORREF m_colorWindow; // 背景色 92 COLORREF m_colorHighlight; 93 COLORREF m_colorShadow; 94 COLORREF m_colorButton; 95 COLORREF m_colorText; // 显示文本颜色 96 97 int m_nRadiusFrame; // 仪表盘边框半径 98 //{{AFX_MSG(CMeter) 99 afx_msg void OnPaint(); 100 afx_msg void OnSize(UINT nType, int cx, int cy); 101 //}}AFX_MSG 102 103 DECLARE_MESSAGE_MAP() 104 }; 105 106 ///////////////////////////////////////////////////////////////////////////// 107 108 //{{AFX_INSERT_LOCATION}} 109 // Microsoft Visual C++ will insert additional declarations immediately before the previous line. 110 111 #endif // !defined(AFX_METER_H__D5802279_6502_4453_BE21_58604877AD39__INCLUDED_)
Meter.cpp
1 // Meter.cpp : implementation file 2 // 3 4 #include "stdafx.h" 5 #include "Meter.h" 6 #include "math.h" 7 #include "MemDCEx.h" 8 9 10 #ifdef _DEBUG 11 #define new DEBUG_NEW 12 #undef THIS_FILE 13 static char THIS_FILE[] = __FILE__; 14 #endif 15 16 #define PT_NUM 50 17 ///////////////////////////////////////////////////////////////////////////// 18 // CMeter 19 20 CMeter::CMeter() 21 { 22 m_nStartAngleDeg = 225; 23 m_nEndAngleDeg = 315; 24 m_nTicks = 10; 25 m_nSubTicks = 5; 26 m_dMaxValue = 100.0; 27 m_dMinValue = 0.0; 28 m_dCurrentValue = 00.0; 29 m_nScaleDecimals = 0; 30 m_nValueDecimals = 1; 31 m_colorNeedle = RGB(255, 0, 0); 32 m_strUnits = _T("(KV)"); 33 m_bColorTick = FALSE; 34 35 // 颜色表格 36 m_colorTable[0] = RGB(177,255,99); 37 m_colorTable[1] = RGB(0, 255,0); 38 m_colorTable[2] = RGB(0,123,0); 39 m_colorTable[3] = RGB(230,248, 38); 40 m_colorTable[4] = RGB(253, 138, 29); 41 m_colorTable[5] = RGB(255, 0, 0); 42 } 43 44 CMeter::~CMeter() 45 { 46 } 47 48 49 BEGIN_MESSAGE_MAP(CMeter, CStatic) 50 //{{AFX_MSG_MAP(CMeter) 51 ON_WM_PAINT() 52 ON_WM_SIZE() 53 //}}AFX_MSG_MAP 54 END_MESSAGE_MAP() 55 56 ///////////////////////////////////////////////////////////////////////////// 57 // CMeter message handlers 58 59 void CMeter::OnPaint() 60 { 61 CPaintDC dc(this); // device context for painting 62 63 // 获得控件区域 64 GetClientRect (&m_rectCtrl); 65 66 CMemDCEx memDC(&dc, &m_rectCtrl); 67 68 // 选取圆盘边框半径 69 m_nRadiusFrame = max(m_rectCtrl.Height(), m_rectCtrl.Width())*9/21; 70 71 // 获得仪表盘中心点 72 m_ptMeterCenter = m_rectCtrl.CenterPoint(); 73 m_ptMeterCenter.y += m_nRadiusFrame/10; 74 75 //绘制仪表盘 76 if(m_dcBackground.GetSafeHdc()== NULL|| (m_bitmapBackground.m_hObject == NULL)) 77 { 78 m_dcBackground.CreateCompatibleDC(&dc); 79 m_bitmapBackground.CreateCompatibleBitmap(&dc, m_rectCtrl.Width(), m_rectCtrl.Height()) ; 80 m_pBitmapOldBackground = m_dcBackground.SelectObject(&m_bitmapBackground) ; 81 DrawMeterBackground(&m_dcBackground, m_rectCtrl); 82 83 } 84 memDC.BitBlt(0, 0, m_rectCtrl.Width(), m_rectCtrl.Height(), 85 &m_dcBackground, 0, 0, SRCCOPY) ; 86 87 // 绘制指针 88 DrawNeedle(&memDC); 89 90 DrawNode(&memDC); 91 92 DrawValue(&memDC); 93 // Do not call CStatic::OnPaint() for painting messages 94 } 95 96 void CMeter::DrawMeterBackground(CDC *pDC, CRect &rect) 97 { 98 int nInnerRadius = m_nRadiusFrame*8/10; // 内圆弧半径 99 100 m_nCenterRadius = m_nRadiusFrame/20; // 中心园半径大小 101 102 int nFrame = m_nRadiusFrame/18; // 边框厚度 103 104 double dstepTickDeg = (360.0+m_nStartAngleDeg-m_nEndAngleDeg)/(m_nTicks*m_nSubTicks); // 刻度步进角度 105 106 int nSubTickR = nInnerRadius+(m_nRadiusFrame-2*nFrame-nInnerRadius)/2; 107 108 double dDeg = (m_nStartAngleDeg+360.0-m_nEndAngleDeg)/(TABNUM*PT_NUM); 109 110 111 CRect rectPanel,rectInnerPanel; 112 CPen penDraw, *pPenOld; 113 CFont *pFontOld; 114 CBrush brushFill, *pBrushOld; 115 POINT ptStart, ptEnd, ptInnerStart, ptInnerEnd; 116 CPoint pointInner[BOUNDARY_POINTS], ptGroup1[PT_NUM*TABNUM+1], ptGroup2[PT_NUM*TABNUM+1]; 117 CPoint ptRgn[PT_NUM*2+2]; 118 CPoint pttemp; 119 CString strtemp; 120 double dRadPerDeg; 121 double dTickAngleRad; 122 double dTemp; 123 int nRef = 0; 124 int nTickAngle; 125 int nHeight; // 字体大小 126 double dtempangle; 127 128 // 计算起始角终止角弧度 129 dRadPerDeg = 4.0*atan(1.0)/180.0; 130 m_dLeftAngleRad = (m_nStartAngleDeg-180.0)*dRadPerDeg; 131 m_dRightAngleRad = (m_nEndAngleDeg-360.0)*dRadPerDeg; 132 133 // 计算圆弧起始终止点及区域 134 ptStart.x = m_ptMeterCenter.x-(int)(m_nRadiusFrame*cos(m_dLeftAngleRad)); 135 ptStart.y = m_ptMeterCenter.y+(int)(m_nRadiusFrame*sin(m_dLeftAngleRad)); 136 ptEnd.x = m_ptMeterCenter.x+(int)(m_nRadiusFrame*cos(-m_dRightAngleRad)); 137 ptEnd.y = m_ptMeterCenter.y+(int)(m_nRadiusFrame*sin(-m_dRightAngleRad)); 138 139 rectPanel.SetRect(m_ptMeterCenter.x-m_nRadiusFrame, m_ptMeterCenter.y-m_nRadiusFrame, 140 m_ptMeterCenter.x+m_nRadiusFrame, m_ptMeterCenter.y+m_nRadiusFrame); 141 // 获取点的位置 142 for(int i=0; i<=PT_NUM*TABNUM; i++) 143 { 144 ptGroup1[i].x = m_ptMeterCenter.x + (int)((m_nRadiusFrame-nFrame)*cos((m_nStartAngleDeg-i*dDeg)*dRadPerDeg)); 145 ptGroup1[i].y = m_ptMeterCenter.y - (int)((m_nRadiusFrame-nFrame)*sin((m_nStartAngleDeg-i*dDeg)*dRadPerDeg)); 146 ptGroup2[i].x = m_ptMeterCenter.x + (int)(m_nRadiusFrame*8*cos((m_nStartAngleDeg-i*dDeg)*dRadPerDeg)/10); 147 ptGroup2[i].y = m_ptMeterCenter.y - (int)(m_nRadiusFrame*8*sin((m_nStartAngleDeg-i*dDeg)*dRadPerDeg)/10); 148 } 149 150 // 获取系统颜色; 151 m_colorWindow = GetSysColor(COLOR_WINDOW); 152 m_colorButton = GetSysColor(COLOR_BTNFACE); 153 m_colorShadow = GetSysColor(COLOR_BTNSHADOW); 154 m_colorHighlight = GetSysColor(COLOR_BTNHIGHLIGHT); 155 m_colorText = GetSysColor(COLOR_BTNTEXT); 156 // 临时使用的颜色 157 COLORREF colorCaption, cEdge, cMiddle; 158 cMiddle = RGB(255, 255, 255); 159 cEdge = RGB(96, 96, 255); 160 161 // 用按钮色绘制背景 162 brushFill.DeleteObject(); 163 brushFill.CreateSolidBrush(m_colorButton); 164 pBrushOld = pDC->SelectObject(&brushFill); 165 pDC->Rectangle(rect); 166 pDC->SelectObject(pBrushOld); 167 168 // 绘制圆盘边框 169 170 for(int iOnBand=nFrame; iOnBand>0; iOnBand--) 171 { 172 penDraw.DeleteObject(); 173 colorCaption = RGB((GetRValue(cEdge)-GetRValue(cMiddle))*((float)iOnBand)/nFrame+GetRValue(cMiddle), 174 (GetGValue(cEdge)-GetGValue(cMiddle))*((float)iOnBand)/nFrame+GetGValue(cMiddle), 175 (GetBValue(cEdge)-GetBValue(cMiddle))*((float)iOnBand)/nFrame+GetBValue(cMiddle)); 176 penDraw.CreatePen(PS_SOLID, iOnBand*2, colorCaption); 177 pPenOld = pDC->SelectObject(&penDraw); 178 pDC->Arc(&rectPanel, ptEnd, ptStart); 179 pDC->SelectObject(pPenOld); 180 } 181 // 绘制内圈 182 ptInnerStart.x = m_ptMeterCenter.x-(int)(nInnerRadius*cos(m_dLeftAngleRad)); 183 ptInnerStart.y = m_ptMeterCenter.y+(int)(nInnerRadius*sin(m_dLeftAngleRad)); 184 ptInnerEnd.x = m_ptMeterCenter.x+(int)(nInnerRadius*cos(-m_dRightAngleRad)); 185 ptInnerEnd.y = m_ptMeterCenter.y+(int)(nInnerRadius*sin(-m_dRightAngleRad)); 186 187 rectInnerPanel.SetRect(m_ptMeterCenter.x-nInnerRadius, m_ptMeterCenter.y-nInnerRadius, 188 m_ptMeterCenter.x+nInnerRadius ,m_ptMeterCenter.y+nInnerRadius); 189 190 penDraw.DeleteObject(); 191 penDraw.CreatePen(PS_SOLID, 1, RGB(255,255,0)); 192 pPenOld = pDC->SelectObject(&penDraw); 193 pDC->Arc(&rectInnerPanel, ptInnerEnd, ptInnerStart); 194 pDC->SelectObject(pPenOld); 195 196 if(m_bColorTick) 197 { 198 199 // 绘制色彩刻度 200 for(int i=0; i<TABNUM; i++) 201 { 202 //确定区域 203 for(int j=0; j<=PT_NUM; j++) 204 { 205 ptRgn[j] = ptGroup1[i*PT_NUM+j]; 206 ptRgn[2*PT_NUM+1-j] = ptGroup2[i*PT_NUM+j]; 207 } 208 brushFill.DeleteObject(); 209 brushFill.CreateSolidBrush(m_colorTable[i]); 210 pBrushOld = pDC->SelectObject(&brushFill); 211 penDraw.DeleteObject(); 212 penDraw.CreatePen(PS_SOLID, 1, m_colorTable[i]); 213 pPenOld = pDC->SelectObject(&penDraw); 214 pDC->Polygon(ptRgn, 2*PT_NUM+2); 215 pDC->SelectObject(pBrushOld); 216 pDC->SelectObject(pPenOld); 217 } 218 219 } 220 221 // 计算刻度点,避免不能整除引起较大误差*100 222 for(nTickAngle=m_nStartAngleDeg*100; nTickAngle>=(m_nEndAngleDeg-360)*100; nTickAngle-=(int)(dstepTickDeg*100)) 223 { 224 // 转换成弧度 225 dTickAngleRad = (double)nTickAngle/100*dRadPerDeg; 226 // 确定外圈坐标 227 // 确定x坐标 228 dTemp = m_ptMeterCenter.x + (m_nRadiusFrame-2*nFrame)*cos(dTickAngleRad); 229 m_pointBoundary[nRef].x = ROUND(dTemp); 230 // 确定y坐标 231 dTemp = m_ptMeterCenter.y - (m_nRadiusFrame-2*nFrame)*sin(dTickAngleRad); 232 m_pointBoundary[nRef].y = ROUND(dTemp); 233 234 // 确定刻度点(主刻度和子刻度) 235 //主刻度及文本标注点 236 if(nRef%m_nSubTicks == 0) 237 { 238 dTemp = m_ptMeterCenter.x + nInnerRadius*cos(dTickAngleRad); 239 pointInner[nRef].x = ROUND(dTemp); 240 dTemp = m_ptMeterCenter.y - nInnerRadius*sin(dTickAngleRad); 241 pointInner[nRef].y = ROUND(dTemp); 242 } 243 // 子刻度 244 else 245 { 246 dTemp = m_ptMeterCenter.x + nSubTickR*cos(dTickAngleRad); 247 pointInner[nRef].x = ROUND(dTemp); 248 dTemp = m_ptMeterCenter.y - nSubTickR*sin(dTickAngleRad); 249 pointInner[nRef].y = ROUND(dTemp); 250 } 251 nRef++ ; 252 } 253 // 多边形区域 254 m_rgnBoundary.DeleteObject() ; 255 m_rgnBoundary.CreatePolygonRgn(m_pointBoundary, nRef, ALTERNATE); 256 257 m_rectValue.top = m_ptMeterCenter.y + m_nRadiusFrame/5; 258 m_rectValue.bottom = m_ptMeterCenter.y + m_nRadiusFrame/2; 259 m_rectValue.left = m_ptMeterCenter.x - m_nRadiusFrame/2; 260 m_rectValue.right = m_ptMeterCenter.x + m_nRadiusFrame/2; 261 262 // 绘制刻度 263 penDraw.DeleteObject(); 264 penDraw.CreatePen(PS_SOLID, 1, RGB(0,0,0)); 265 pPenOld = pDC->SelectObject(&penDraw); 266 for(int i=0; i<nRef; i++) 267 { 268 pDC->MoveTo(m_pointBoundary[i]); 269 pDC->LineTo(pointInner[i]); 270 } 271 pDC->SelectObject(pPenOld); 272 273 // 刻度标号 274 275 nHeight = m_nRadiusFrame/8; //字体大小 276 m_font.CreateFont(nHeight, 0, 0, 0, 550, 277 FALSE, FALSE, 0, ANSI_CHARSET, 278 OUT_DEFAULT_PRECIS, 279 CLIP_DEFAULT_PRECIS, 280 DEFAULT_QUALITY, 281 DEFAULT_PITCH|FF_SWISS, "Arial"); 282 283 pFontOld = pDC->SelectObject(&m_font); 284 pDC->SetBkMode(TRANSPARENT); 285 for(int i=0; i<=m_nTicks; i++) 286 { 287 dtempangle = m_nStartAngleDeg-i*m_nSubTicks*dstepTickDeg; 288 strtemp.Format("%.*lf", m_nScaleDecimals, (m_dMinValue+(m_dMaxValue-m_dMinValue)*i/m_nTicks)); 289 290 if(dtempangle>190) 291 { 292 pDC->SetTextAlign(TA_BOTTOM|TA_LEFT); 293 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y+nHeight/2, strtemp); 294 } 295 296 else if(dtempangle>170) 297 { 298 pDC->SetTextAlign(TA_BASELINE|TA_LEFT); 299 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y+nHeight/3, strtemp); 300 } 301 else if(dtempangle>135) 302 { 303 pDC->SetTextAlign(TA_BASELINE|TA_LEFT); 304 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y+nHeight/2, strtemp); 305 } 306 else if(dtempangle>100) 307 { 308 pDC->SetTextAlign(TA_TOP|TA_LEFT); 309 pDC->TextOut(pointInner[m_nSubTicks*i].x-nHeight/4, pointInner[m_nSubTicks*i].y-nHeight/8, strtemp); 310 } 311 312 else if(dtempangle>80) 313 { 314 pDC->SetTextAlign(TA_TOP|TA_CENTER); 315 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y, strtemp); 316 } 317 else if(dtempangle>45) 318 { 319 pDC->SetTextAlign(TA_BOTTOM|TA_RIGHT); 320 pDC->TextOut(pointInner[m_nSubTicks*i].x+nHeight/3, pointInner[m_nSubTicks*i].y+nHeight, strtemp); 321 } 322 else if(dtempangle>10) 323 { 324 pDC->SetTextAlign(TA_RIGHT|TA_BASELINE); 325 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y+nHeight/2, strtemp); 326 } 327 else if(dtempangle>-10) 328 { 329 pDC->SetTextAlign(TA_RIGHT|TA_BASELINE); 330 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y+nHeight/3, strtemp); 331 } 332 else 333 { 334 pDC->SetTextAlign(TA_RIGHT|TA_BOTTOM); 335 pDC->TextOut(pointInner[m_nSubTicks*i].x, pointInner[m_nSubTicks*i].y+nHeight/2, strtemp); 336 } 337 } 338 pDC->SelectObject(pFontOld); 339 340 } 341 342 void CMeter::ReconstructControl() 343 { 344 if ((m_pBitmapOldBackground) && 345 (m_bitmapBackground.GetSafeHandle()) && 346 (m_dcBackground.GetSafeHdc())) 347 { 348 m_dcBackground.SelectObject(m_pBitmapOldBackground); 349 m_dcBackground.DeleteDC() ; 350 m_bitmapBackground.DeleteObject(); 351 } 352 353 Invalidate (); 354 } 355 356 void CMeter::OnSize(UINT nType, int cx, int cy) 357 { 358 CStatic::OnSize(nType, cx, cy); 359 360 // TODO: Add your message handler code here 361 ReconstructControl() ; 362 } 363 364 void CMeter::DrawNeedle(CDC *pDC) 365 { 366 int nResult; 367 double dRadPerDeg = 4.0*atan(1.0)/180.0; 368 double dAngleDeg; 369 double dAngleRad ; 370 double dTemp ; 371 CBrush brushFill, *pBrushOld ; 372 CPen penDraw, *pPenOld ; 373 CPoint pointNeedle[4] ; // 指针由四边形组成 374 375 376 // 计算角度并限定指针走的角度 377 dAngleDeg = m_nStartAngleDeg-(360.0+m_nStartAngleDeg-m_nEndAngleDeg) 378 *(m_dCurrentValue-m_dMinValue)/(m_dMaxValue-m_dMinValue); 379 dAngleDeg = min(dAngleDeg, m_nStartAngleDeg); 380 dAngleDeg = max(dAngleDeg, m_nEndAngleDeg-360.0); 381 dAngleRad = dAngleDeg*dRadPerDeg; 382 383 // 计算三角形底边两个点 384 pointNeedle[0].x = m_ptMeterCenter.x - (int)(m_nCenterRadius*10*sin(dAngleRad)/8); 385 pointNeedle[0].y = m_ptMeterCenter.y - (int)(m_nCenterRadius*10*cos(dAngleRad)/8); 386 pointNeedle[2].x = m_ptMeterCenter.x + (int)(m_nCenterRadius*10*sin(dAngleRad)/8); 387 pointNeedle[2].y = m_ptMeterCenter.y + (int)(m_nCenterRadius*10*cos(dAngleRad)/8); 388 389 // 计算指针顶部坐标 390 dTemp = m_ptMeterCenter.x + m_nRadiusFrame*cos(dAngleRad)*95/100; 391 pointNeedle[1].x = ROUND(dTemp); 392 dTemp = m_ptMeterCenter.y - m_nRadiusFrame*sin(dAngleRad)*95/100; 393 pointNeedle[1].y = ROUND(dTemp); 394 // 计算指针尾部坐标 395 dTemp = m_ptMeterCenter.x - m_nRadiusFrame*cos(dAngleRad)/6; 396 pointNeedle[3].x = ROUND(dTemp); 397 dTemp = m_ptMeterCenter.y + m_nRadiusFrame*sin(dAngleRad)/6; 398 pointNeedle[3].y = ROUND(dTemp); 399 400 pDC->SelectClipRgn(&m_rgnBoundary); 401 402 brushFill.CreateSolidBrush(m_colorNeedle); 403 penDraw.CreatePen(PS_SOLID, 1, m_colorNeedle); 404 405 pPenOld = pDC->SelectObject(&penDraw) ; 406 pBrushOld = pDC->SelectObject(&brushFill) ; 407 408 // 绘制指针 409 pDC->Polygon(pointNeedle, 4); 410 411 nResult = pDC->SelectClipRgn(NULL); 412 413 pDC->SelectObject(pPenOld); 414 pDC->SelectObject(pBrushOld); 415 416 // 立体感处理 417 if(dAngleDeg>90) 418 { 419 penDraw.DeleteObject(); 420 penDraw.CreatePen(PS_SOLID, 2, m_colorShadow); 421 pPenOld = pDC->SelectObject(&penDraw); 422 pDC->MoveTo(pointNeedle[1]); 423 pDC->LineTo(pointNeedle[0]); 424 pDC->LineTo(pointNeedle[3]); 425 pDC->SelectObject(pPenOld); 426 427 penDraw.DeleteObject(); 428 penDraw.CreatePen(PS_SOLID, 1, m_colorHighlight); 429 pPenOld = pDC->SelectObject(&penDraw); 430 pDC->MoveTo(pointNeedle[1]); 431 pDC->LineTo(pointNeedle[2]); 432 pDC->LineTo(pointNeedle[3]); 433 pDC->SelectObject(pPenOld); 434 } 435 else 436 { 437 penDraw.DeleteObject(); 438 penDraw.CreatePen(PS_SOLID, 2, m_colorShadow); 439 pPenOld = pDC->SelectObject(&penDraw); 440 pDC->MoveTo(pointNeedle[1]); 441 pDC->LineTo(pointNeedle[2]); 442 pDC->LineTo(pointNeedle[3]); 443 pDC->SelectObject(pPenOld); 444 445 penDraw.DeleteObject(); 446 penDraw.CreatePen(PS_SOLID, 1, m_colorHighlight); 447 pPenOld = pDC->SelectObject(&penDraw); 448 pDC->MoveTo(pointNeedle[1]); 449 pDC->LineTo(pointNeedle[0]); 450 pDC->LineTo(pointNeedle[3]); 451 pDC->SelectObject(pPenOld); 452 } 453 } 454 455 void CMeter::UpdateNeedle(double dValue) 456 { 457 m_dCurrentValue = dValue; 458 Invalidate(); 459 } 460 461 void CMeter::SetNeedleColor(COLORREF colorNeedle) 462 { 463 m_colorNeedle = colorNeedle ; 464 ReconstructControl() ; 465 } 466 467 468 void CMeter::SetRange(double dMin, double dMax) 469 { 470 m_dMaxValue = dMax ; 471 m_dMinValue = dMin ; 472 ReconstructControl() ; 473 } 474 475 476 void CMeter::SetScaleDecimals(int nDecimals) 477 { 478 m_nScaleDecimals = nDecimals ; 479 ReconstructControl() ; 480 } 481 482 void CMeter::SetUnits(CString &strUnits) 483 { 484 m_strUnits = strUnits ; 485 ReconstructControl() ; 486 } 487 488 void CMeter::SetValueDecimals(int nDecimals) 489 { 490 m_nValueDecimals = nDecimals ; 491 ReconstructControl() ; 492 } 493 494 495 496 497 498 void CMeter::DrawNode(CDC *pDC) 499 { 500 CPen penDraw, *pPenOld; 501 COLORREF cEdge, cMiddle, cNode; 502 cMiddle = RGB(255, 255, 255); 503 cEdge = RGB(0, 0, 0); 504 for(int i=m_nCenterRadius*3/4; i>=0; i--) 505 { 506 cNode = RGB((GetRValue(cEdge)-GetRValue(cMiddle))*((float)i)*4/(3*m_nCenterRadius)+GetRValue(cMiddle), 507 (GetGValue(cEdge)-GetGValue(cMiddle))*((float)i)*4/(3*m_nCenterRadius)+GetGValue(cMiddle), 508 (GetBValue(cEdge)-GetBValue(cMiddle))*((float)i)*4/(3*m_nCenterRadius)+GetBValue(cMiddle)); 509 510 penDraw.DeleteObject(); 511 penDraw.CreatePen(PS_SOLID, 1, cNode); 512 pPenOld = pDC->SelectObject(&penDraw); 513 pDC->Arc(m_ptMeterCenter.x-i, m_ptMeterCenter.y-i,m_ptMeterCenter.x+i,m_ptMeterCenter.y+i, 514 m_ptMeterCenter.x-i,m_ptMeterCenter.y,m_ptMeterCenter.x-i,m_ptMeterCenter.y); 515 pDC->SelectObject(pPenOld); 516 } 517 } 518 519 void CMeter::SetColorTick(BOOL bColorTick) 520 { 521 m_bColorTick = bColorTick; 522 ReconstructControl(); 523 } 524 525 void CMeter::DrawValue(CDC *pDC) 526 { 527 int nHeight; 528 CPoint pttemp; 529 CString strtemp; 530 CFont *pFontOld; 531 532 // 数值显示 533 nHeight = m_nRadiusFrame/4; 534 pttemp = m_rectValue.CenterPoint(); 535 strtemp.Format("%.*lf", m_nValueDecimals, m_dCurrentValue); 536 m_font.DeleteObject() ; 537 m_font.CreateFont (nHeight, 0, 0, 0, 550, 538 FALSE, FALSE, 0, ANSI_CHARSET, 539 OUT_DEFAULT_PRECIS, 540 CLIP_DEFAULT_PRECIS, 541 DEFAULT_QUALITY, 542 DEFAULT_PITCH|FF_SWISS, "Arial") ; 543 pFontOld = pDC->SelectObject(&m_font); 544 pDC->SetBkColor(m_colorButton); 545 pDC->SetTextAlign(TA_TOP|TA_CENTER); 546 pDC->TextOut(pttemp.x, pttemp.y, m_strUnits); 547 pDC->TextOut(pttemp.x, pttemp.y+nHeight, strtemp); 548 // 恢复字体和背景色 549 pDC->SelectObject(pFontOld); 550 pDC->SetBkColor(m_colorWindow); 551 } 552 553 void CMeter::SetTicks(int nTicks) 554 { 555 m_nTicks = nTicks; 556 ReconstructControl(); 557 } 558 559 void CMeter::SetSubTicks(int nSubTicks) 560 { 561 m_nSubTicks = nSubTicks; 562 ReconstructControl(); 563 } 564 565 void CMeter::SetAngleRange(int nStartAngleDeg, int nEndAngleDeg) 566 { 567 m_nStartAngleDeg = nStartAngleDeg; 568 m_nEndAngleDeg = nEndAngleDeg; 569 ReconstructControl(); 570 }
MemDCEx.h
1 #ifndef _MEMDC_H_ 2 #define _MEMDC_H_ 3 4 ////////////////////////////////////////////////// 5 // CMemDC - memory DC 6 // 7 // Author: Keith Rule 8 // Email: keithr@europa.com 9 // Copyright 1996-1999, Keith Rule 10 // 11 // You may freely use or modify this code provided this 12 // Copyright is included in all derived versions. 13 // 14 // History - 10/3/97 Fixed scrolling bug. 15 // Added print support. - KR 16 // 17 // 11/3/99 Fixed most common complaint. Added 18 // background color fill. - KR 19 // 20 // 11/3/99 Added support for mapping modes other than 21 // MM_TEXT as suggested by Lee Sang Hun. - KR 22 // 23 // Modified by Mark Malburg March 12, 1998 24 // Email: mcmalburg@sytech.cummins.com 25 // (added new construction and clipboard handling) 26 // 27 // Construction : 28 // | 29 // | CMemDC pDC (dc, &drawRect, toMemDC) ; 30 // | 31 // | where: 32 // | "dc" - pointer to the CDC that is an argument to OnDraw 33 // | "drawRect" - pointer to the rectangle to draw in 34 // | "boolToMemory" - TRUE: to the client, FALSE: to clipboard or printer 35 // | 36 // 37 // This class implements a memory Device Context which allows 38 // flicker free drawing. 39 40 class CMemDCEx : public CDC 41 { 42 private: 43 CBitmap m_bitmap; // Offscreen bitmap 44 CBitmap* m_oldBitmap; // bitmap originally found in CMemDC 45 CDC* m_pDC; // Saves CDC passed in constructor 46 CRect m_rect; // Rectangle of drawing area. 47 BOOL m_bMemDC; // TRUE if CDC really is a Memory DC. 48 public: 49 50 CMemDCEx(CDC* pDC, const CRect* pRect = NULL, bool boolToMemory = TRUE) : CDC() 51 { 52 ASSERT(pDC != NULL); 53 54 // Some initialization 55 m_pDC = pDC; 56 m_oldBitmap = NULL; 57 if (boolToMemory) 58 m_bMemDC = !pDC->IsPrinting(); 59 else 60 m_bMemDC = FALSE ; 61 62 // Get the rectangle to draw 63 if (pRect == NULL) 64 { 65 pDC->GetClipBox(&m_rect); 66 } 67 else 68 { 69 m_rect = *pRect; 70 } 71 72 if (m_bMemDC) 73 { 74 // Create a Memory DC 75 CreateCompatibleDC(pDC); 76 pDC->LPtoDP(&m_rect); 77 78 m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height()); 79 m_oldBitmap = SelectObject(&m_bitmap); 80 81 SetMapMode(pDC->GetMapMode()); 82 pDC->DPtoLP(&m_rect); 83 SetWindowOrg(m_rect.left, m_rect.top); 84 } 85 else 86 { 87 // Make a copy of the relevent parts of the current DC for printing 88 if (pDC->IsPrinting()) 89 m_bPrinting = pDC->m_bPrinting; 90 m_hDC = pDC->m_hDC; 91 m_hAttribDC = pDC->m_hAttribDC; 92 } 93 94 // Fill background 95 FillSolidRect(m_rect, pDC->GetBkColor()); 96 } 97 98 99 ~CMemDCEx() 100 { 101 if (m_bMemDC) 102 { 103 // Copy the offscreen bitmap onto the screen. 104 m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), 105 this, m_rect.left, m_rect.top, SRCCOPY); 106 107 //Swap back the original bitmap. 108 SelectObject(m_oldBitmap); 109 } 110 else 111 { 112 // All we need to do is replace the DC with an illegal value, 113 // this keeps us from accidently deleting the handles associated with 114 // the CDC that was passed to the constructor. 115 m_hDC = m_hAttribDC = NULL; 116 } 117 } 118 119 // Allow usage as a pointer 120 CMemDCEx* operator->() 121 { 122 return this; 123 } 124 125 // Allow usage as a pointer 126 operator CMemDCEx*() 127 { 128 return this; 129 } 130 }; 131 132 #endif
完整工程下载:https://download.csdn.net/download/qq_23565865/10715458