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; iSelectObject(&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; nAngleDegMoveTo(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) ;//重绘指针 
}