⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wymeterctl.cpp

📁 西安电子科技大学王亚民教授所著《组态软件设计与开发》附带的源代码06章
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "stdafx.h"
#include "Meter.h"
#include "wyMeterCtl.h"
#include "wyMeterPpg.h"
#include <math.h>

#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) ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -