📄 wymeterctl.cpp
字号:
#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 + -