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

原文地址:https://www.cnblogs.com/qiwu1314/p/9776736.html