www.pudn.com > 组态软件的ActiveX控件设计r.rar > wyMeterCtl.cpp
#include "stdafx.h" #include "Meter.h" #include "wyMeterCtl.h" #include "wyMeterPpg.h" #include#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CwyMeterCtrl, COleControl) // 消息映射 BEGIN_MESSAGE_MAP(CwyMeterCtrl, COleControl) //{{AFX_MSG_MAP(CwyMeterCtrl) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_TIMER() //}}AFX_MSG_MAP ON_MESSAGE(OCM_COMMAND, OnOcmCommand) ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit) ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties) END_MESSAGE_MAP() // 调度映射 BEGIN_DISPATCH_MAP(CwyMeterCtrl, COleControl) //{{AFX_DISPATCH_MAP(CwyMeterCtrl) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "dMaxValue", m_dMaxValue, OnDMaxValueChanged, VT_R8) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "dMinValue", m_dMinValue, OnDMinValueChanged, VT_R8) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "dCurrentValue", m_dCurrentValue, OnDCurrentValueChanged, VT_R8) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "nScaleDecimals", m_nScaleDecimals, OnNScaleDecimalsChanged, VT_I2) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "nValueDecimals", m_nValueDecimals, OnNValueDecimalsChanged, VT_I2) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "colorNeedle", m_colorNeedle, OnColorNeedleChanged, VT_COLOR) DISP_PROPERTY_NOTIFY(CwyMeterCtrl, "strUnits", m_strUnits, OnStrUnitsChanged, VT_BSTR) DISP_FUNCTION(CwyMeterCtrl, "SetCurrentValue", SetCurrentValue, VT_EMPTY, VTS_R8) //}}AFX_DISPATCH_MAP DISP_FUNCTION_ID(CwyMeterCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE) END_DISPATCH_MAP() // 事件映射 BEGIN_EVENT_MAP(CwyMeterCtrl, COleControl) //{{AFX_EVENT_MAP(CwyMeterCtrl) //}}AFX_EVENT_MAP END_EVENT_MAP() // 属性页 BEGIN_PROPPAGEIDS(CwyMeterCtrl, 1) PROPPAGEID(CwyMeterPropPage::guid) END_PROPPAGEIDS(CwyMeterCtrl) // 初始化类工厂和 GUID IMPLEMENT_OLECREATE_EX(CwyMeterCtrl, "METER.wyMeterCtrl.1", 0x15491a65, 0x5b63, 0x11d5, 0xad, 0xd3, 0, 0x10, 0x88, 0xab, 0x5d, 0x33) // 类型库 ID 和 版本 IMPLEMENT_OLETYPELIB(CwyMeterCtrl, _tlid, _wVerMajor, _wVerMinor) // 接口 IDs const IID BASED_CODE IID_DwyMeter = { 0x15491a63, 0x5b63, 0x11d5, { 0xad, 0xd3, 0, 0x10, 0x88, 0xab, 0x5d, 0x33 } }; const IID BASED_CODE IID_DwyMeterEvents = { 0x15491a64, 0x5b63, 0x11d5, { 0xad, 0xd3, 0, 0x10, 0x88, 0xab, 0x5d, 0x33 } }; // 控件类型信息 static const DWORD BASED_CODE _dwwyMeterOleMisc = OLEMISC_ACTIVATEWHENVISIBLE | OLEMISC_SETCLIENTSITEFIRST | OLEMISC_INSIDEOUT | OLEMISC_CANTLINKINSIDE | OLEMISC_RECOMPOSEONRESIZE; IMPLEMENT_OLECTLTYPE(CwyMeterCtrl, IDS_WYMETER, _dwwyMeterOleMisc) // 增加和删除系统注册记录 BOOL CwyMeterCtrl::CwyMeterCtrlFactory::UpdateRegistry(BOOL bRegister) { // 注册控件 if (bRegister) return AfxOleRegisterControlClass( AfxGetInstanceHandle(), m_clsid, m_lpszProgID, IDS_WYMETER, IDB_WYMETER, afxRegInsertable | afxRegApartmentThreading, _dwwyMeterOleMisc, _tlid, _wVerMajor, _wVerMinor); else return AfxOleUnregisterClass(m_clsid, m_lpszProgID); } //控件构造函数 CwyMeterCtrl::CwyMeterCtrl() { InitializeIIDs(&IID_DwyMeter, &IID_DwyMeterEvents); //设定控件的初始大小 SetInitialSize( 90, 90 ); } //控件析构函数 CwyMeterCtrl::~CwyMeterCtrl() { } //控件绘制函数 void CwyMeterCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) { // DoSuperclassPaint(pdc, rcBounds); CBrush brush(TranslateColor(GetBackColor())); pdc->FillRect(rcBounds,&brush); DrawMeterBackground(pdc, rcBounds) ; DrawNeedle(pdc) ; DrawValue(pdc) ; } // 持久性支持 void CwyMeterCtrl::DoPropExchange(CPropExchange* pPX) { ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); COleControl::DoPropExchange(pPX); PX_Color(pPX,"colorNeedle",m_colorNeedle,RGB(255,0,0)); PX_String(pPX,"strUnits" ,m_strUnits,"v"); PX_Short(pPX,"nScaleDecimals" ,m_nScaleDecimals,0); PX_Short(pPX,"nValueDecimals" ,m_nValueDecimals,1); PX_Double(pPX,"dMaxValue" ,m_dMaxValue,10.0); PX_Double(pPX,"dMinValue" ,m_dMinValue,0.0); PX_Double(pPX,"dCurrentValue" ,m_dCurrentValue,0.0); } // 恢复初始状态 void CwyMeterCtrl::OnResetState() { COleControl::OnResetState(); // Resets defaults found in DoPropExchange } //显示About对话框 void CwyMeterCtrl::AboutBox() { CDialog dlgAbout(IDD_ABOUTBOX_WYMETER); dlgAbout.DoModal(); } // 设置窗口初始参数 BOOL CwyMeterCtrl::PreCreateWindow(CREATESTRUCT& cs) { cs.lpszClass = _T("STATIC"); return COleControl::PreCreateWindow(cs); } // 说明是否使用基类控件 BOOL CwyMeterCtrl::IsSubclassedControl() { return TRUE; } //处理命令消息 LRESULT CwyMeterCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam) { #ifdef _WIN32 WORD wNotifyCode = HIWORD(wParam); #else WORD wNotifyCode = HIWORD(lParam); #endif return 0; } //绘制指针 void CwyMeterCtrl::DrawNeedle(CDC *pDC) { int nResult ; double dAngleRad ; double dTemp ; CBrush brushFill, *pBrushOld ; CPen penDraw, *pPenOld ; CPoint pointNeedle[3] ; //这个函数绘制三角指针.基本指针是一个水平线,它通过弧线的中点 //绘制在仪表上,指尖所在的角度通过当前值和标尺计算得到. //指针由三点构成的多边形组成,三角形绘制在仪表的区域内. // 计算指针的第一个和最后一个点 pointNeedle[0].x = m_nBottomCX + m_nBottomRadius/20 ; pointNeedle[0].y = m_nBottomCY ; pointNeedle[2].x = m_nBottomCX - m_nBottomRadius/20 ; pointNeedle[2].y = m_nBottomCY ; // 计算指尖的角度 dAngleRad = (m_dCurrentValue-m_dMinValue)*(m_dRightAngleRad-m_dLeftAngleRad)/ (m_dMaxValue-m_dMinValue) + m_dLeftAngleRad ; // 如果角度超出仪表,使用最大或最小角度 dAngleRad = max(dAngleRad, m_dRightAngleRad) ; dAngleRad = min(dAngleRad, m_dLeftAngleRad) ; // 计算指尖的 X 坐标 dTemp = m_nBottomCX + m_nTopRadius*cos(dAngleRad) ; pointNeedle[1].x = ROUND(dTemp) ; // 计算指尖的 Y 坐标 dTemp = m_nBottomCY - m_nTopRadius*sin(dAngleRad) ; pointNeedle[1].y = ROUND(dTemp) ; // 基于仪表选择剪贴区域 pDC->SelectClipRgn(&m_rgnBoundary) ; // 按照指针颜色创建画笔和刷子 brushFill.CreateSolidBrush(m_colorNeedle) ; penDraw.CreatePen(PS_SOLID, 1, m_colorNeedle) ; // 选择画笔和刷子 pPenOld = pDC->SelectObject(&penDraw) ; pBrushOld = pDC->SelectObject(&brushFill) ; // 绘制指针 pDC->Polygon(pointNeedle, 3) ; // 恢复剪贴区域 nResult = pDC->SelectClipRgn(NULL) ; // 恢复画笔和刷子 pDC->SelectObject(pPenOld) ; pDC->SelectObject(pBrushOld) ; } //输出数值 void CwyMeterCtrl::DrawValue(CDC *pDC) { CFont *pFontOld ; CString strTemp ; // 选取字体,字体根据背景大小设定 pFontOld = pDC->SelectObject(&m_fontValue) ; // 设定字体背景色和文本色 pDC->SetTextColor(m_colorText) ; pDC->SetBkColor(m_colorButton) ; // 输出文本,文本与中点和基线对齐 pDC->SetTextAlign(TA_CENTER|TA_BASELINE) ; strTemp.Format("%.*f", m_nValueDecimals, m_dCurrentValue) ; pDC->TextOut(m_nValueCenter, m_nValueBaseline, strTemp) ; // 恢复原背景色和字体 pDC->SetBkColor(m_colorWindow) ; pDC->SelectObject(pFontOld) ; } //绘制背景 void CwyMeterCtrl::DrawMeterBackground(CDC *pDC, const CRect &rect) { int i, nAngleDeg, nRef ; int nHeight ; int nHalfPoints ; int nStartAngleDeg, nEndAngleDeg ; int nTickDeg ; int nAngleIncrementDeg ; double dTemp, dAngleRad, dX, dY ; double dRadPerDeg ; CString strTemp ; CPoint pointRecess[BOUNDARY_POINTS] ; CBrush brushFill, *pBrushOld ; CFont *pFontOld ; CPen penDraw, *pPenOld ; TEXTMETRIC tm ; // 计算仪表半径的中点 m_nBottomCX = rect.right-5; m_nBottomCY = rect.bottom -5; // 计算仪表半径 m_nTopRadius = rect.Height()*6/8 ; m_nBottomRadius = m_nTopRadius/2 ; // 每度表示的弧度数 dRadPerDeg = 4.0*atan(1.0)/180.0 ; // 设置仪表表面区域范围 nStartAngleDeg =90; // 60 ; nEndAngleDeg =180; // 120 ; nTickDeg = 15 ; // 弧上绘制点个数 nAngleIncrementDeg = 5 ; // 角度转换为弧度 m_dLeftAngleRad = nEndAngleDeg*dRadPerDeg ; m_dRightAngleRad = nStartAngleDeg*dRadPerDeg ; // 构造仪表表面区域,它是一个多边形区域 nRef = 0 ; for (nAngleDeg=nStartAngleDeg; nAngleDeg<=nEndAngleDeg; nAngleDeg+=nAngleIncrementDeg) { // 计算当前角度的弧度数 dAngleRad = nAngleDeg*dRadPerDeg ; // 计算 X 坐标 dTemp = m_nBottomCX + m_nTopRadius*cos(dAngleRad) ; m_pointBoundary[nRef].x = ROUND(dTemp) ; // 计算 Y 坐标 dTemp = m_nBottomCY - m_nTopRadius*sin(dAngleRad) ; m_pointBoundary[nRef].y = ROUND(dTemp) ; nRef++ ; } nHalfPoints = nRef ; // 增加低边弧上的点 for (nAngleDeg=nEndAngleDeg; nAngleDeg>=nStartAngleDeg; nAngleDeg-=nAngleIncrementDeg) { dAngleRad = nAngleDeg*dRadPerDeg ; dTemp = m_nBottomCX + m_nBottomRadius*cos(dAngleRad) ; m_pointBoundary[nRef].x = ROUND(dTemp) ; dTemp = m_nBottomCY - m_nBottomRadius*sin(dAngleRad) ; m_pointBoundary[nRef].y = ROUND(dTemp) ; nRef++ ; } // 构造仪表表面多边形 for (i=0; i SelectObject(&brushFill) ; pDC->Rectangle(rect) ; pDC->SelectObject(pBrushOld) ; // 绘制仪表凹面. penDraw.DeleteObject() ; penDraw.CreatePen(PS_SOLID, 1, m_colorShadow) ; pPenOld = pDC->SelectObject(&penDraw) ; pDC->MoveTo(pointRecess[0]) ; pDC->PolylineTo(pointRecess, nHalfPoints+1) ; pDC->SelectObject(pPenOld) ; // 绘制仪表凹面阴影. penDraw.DeleteObject() ; penDraw.CreatePen(PS_SOLID, 1, m_colorHighlight) ; pPenOld = pDC->SelectObject(&penDraw) ; // 绘制低边弧 pDC->PolylineTo(&pointRecess[nHalfPoints], nHalfPoints) ; pDC->LineTo(pointRecess[0]) ; // connect it to the top pDC->SelectObject(pPenOld) ; // 绘制仪表表面 // 使用文本颜色绘制边框 penDraw.DeleteObject() ; penDraw.CreatePen(PS_SOLID, 1, m_colorText) ; pPenOld = pDC->SelectObject(&penDraw) ; // 使用窗口颜色填充 brushFill.DeleteObject() ; brushFill.CreateSolidBrush(m_colorWindow) ; pBrushOld = pDC->SelectObject(&brushFill) ; // 绘制表面 pDC->Polygon(m_pointBoundary, nRef) ; // 恢复刷子 pDC->SelectObject(pBrushOld) ; // 绘制刻度记号. // 刻度长度比高边下降15% dTemp = m_nTopRadius - 0.15*(m_nTopRadius-m_nBottomRadius) ; for (nAngleDeg=90; nAngleDeg>nStartAngleDeg; nAngleDeg-=nTickDeg) { dAngleRad = nAngleDeg*dRadPerDeg ; dX = m_nBottomCX + m_nTopRadius*cos(dAngleRad) ; dY = m_nBottomCY - m_nTopRadius*sin(dAngleRad) ; pDC->MoveTo(ROUND(dX), ROUND(dY)) ; dX = m_nBottomCX + dTemp*cos(dAngleRad) ; dY = m_nBottomCY - dTemp*sin(dAngleRad) ; pDC->LineTo(ROUND(dX), ROUND(dY)) ; } for (nAngleDeg=90+nTickDeg; nAngleDeg MoveTo(ROUND(dX), ROUND(dY)) ; dX = m_nBottomCX + dTemp*cos(dAngleRad) ; dY = m_nBottomCY - dTemp*sin(dAngleRad) ; pDC->LineTo(ROUND(dX), ROUND(dY)) ; } // 恢复画笔 pDC->SelectObject(pPenOld) ; // 绘制数值显示矩形 penDraw.DeleteObject() ; penDraw.CreatePen(PS_SOLID, 1, m_colorShadow) ; pPenOld = pDC->SelectObject(&penDraw) ; pDC->MoveTo(m_rectValue.left, m_rectValue.bottom) ; pDC->LineTo(m_rectValue.left, m_rectValue.top) ; pDC->LineTo(m_rectValue.right, m_rectValue.top) ; pDC->SelectObject(pPenOld) ; penDraw.DeleteObject() ; penDraw.CreatePen(PS_SOLID, 1, m_colorHighlight) ; pPenOld = pDC->SelectObject(&penDraw) ; pDC->LineTo(m_rectValue.right, m_rectValue.bottom) ; pDC->LineTo(m_rectValue.left, m_rectValue.bottom) ; pDC->SelectObject(pPenOld) ; // 计算字体大小 nHeight = m_rectValue.Height()*85/100 ; m_fontValue.DeleteObject() ; m_fontValue.CreateFont (nHeight, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_SWISS, "Arial") ; pFontOld = pDC->SelectObject(&m_fontValue) ; pDC->GetTextMetrics(&tm) ; m_nValueFontHeight = tm.tmHeight ; m_nValueFontWidth = tm.tmAveCharWidth ; m_nValueBaseline = m_rectValue.bottom - m_nValueFontHeight/4 ; m_nValueCenter = m_rectValue.left + m_rectValue.Width()/2 ; // 输出数值 pDC->SetTextColor(m_colorText) ; pDC->SetBkColor(m_colorButton) ; // 输出单位 pDC->SetTextAlign(TA_CENTER|TA_BASELINE) ; pDC->TextOut(rect.right - 2*m_nValueFontWidth, rect.bottom - m_nValueFontHeight/2, m_strUnits) ; // 输出最小值 pDC->SetTextAlign(TA_LEFT|TA_BASELINE) ; strTemp.Format("%.*lf", m_nScaleDecimals, m_dMinValue) ; pDC->TextOut(rect.left+1,rect.bottom-5,strTemp) ; // 输出最大值 pDC->SetTextAlign(TA_RIGHT|TA_BASELINE) ; strTemp.Format("%.*lf", m_nScaleDecimals, m_dMaxValue) ; pDC->TextOut((rect.right+m_pointBoundary[0].x)/2, rect.top+m_nValueFontHeight-3, strTemp) ; // 恢复字体和文字背景色 pDC->SelectObject(pFontOld) ; pDC->SetBkColor(m_colorWindow) ; } //重绘指针 void CwyMeterCtrl::UpdateNeedle(double dValue) { m_dCurrentValue = dValue ; InvalidateControl() ; } // 消息处理 void CwyMeterCtrl::OnDMaxValueChanged() //最大值改变 { InvalidateControl(); SetModifiedFlag(); } void CwyMeterCtrl::OnDMinValueChanged() //最小值改变 { InvalidateControl(); SetModifiedFlag(); } void CwyMeterCtrl::OnDCurrentValueChanged() //当前值改变 { InvalidateControl(); SetModifiedFlag(); } void CwyMeterCtrl::OnNScaleDecimalsChanged() //标尺精度改变 { InvalidateControl(); SetModifiedFlag(); } void CwyMeterCtrl::OnNValueDecimalsChanged() //数值精度改变 { InvalidateControl(); SetModifiedFlag(); } void CwyMeterCtrl::OnColorNeedleChanged() //指针颜色改变 { InvalidateControl(); SetModifiedFlag(); } void CwyMeterCtrl::OnStrUnitsChanged() //数值单位改变 { InvalidateControl(); SetModifiedFlag(); } //串行化 void CwyMeterCtrl::Serialize(CArchive& ar) { if (ar.IsStoring()) { // 保存 ar << m_strUnits; ar << m_dMaxValue; ar << m_dMinValue; ar << m_nScaleDecimals; ar << m_nValueDecimals; ar << m_colorNeedle; } else { // 读取 ar >> m_strUnits; ar >> m_dMaxValue; ar >> m_dMinValue; ar >> m_nScaleDecimals; ar >> m_nValueDecimals; ar >> m_colorNeedle; m_dCurrentValue=0.0; } } //建立窗口时设置定时器 int CwyMeterCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (COleControl::OnCreate(lpCreateStruct) == -1) return -1; SetTimer (1, 1000, NULL) ; return 0; } //关闭窗口时删除定时器 void CwyMeterCtrl::OnDestroy() { COleControl::OnDestroy(); KillTimer (1) ; } //定时消息处理,用于测试 void CwyMeterCtrl::OnTimer(UINT nIDEvent) { //return; static double dStep = 1.5 ; static double dValue = 0.0 ; dValue += dStep ; if (dValue > m_dMaxValue) { dStep = -fabs(dStep) ; dValue = m_dMaxValue-dStep ; } else if (dValue < m_dMinValue) { dStep = fabs(dStep) ; dValue = m_dMinValue+dStep ; } UpdateNeedle(dValue) ; COleControl::OnTimer(nIDEvent); } //设定当前值 void CwyMeterCtrl::SetCurrentValue(double val) { UpdateNeedle(val) ;//重绘指针 }