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

📄 pointerdevice.cpp

📁 上位机图形显示程序,可用于8051单片机的开发,通信及控制
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/////////////////////////////////////////////////////////
//			指针式测量设备PointerDevice封装类
//	版本:1.08
//	最后修改日期:2002.1.25
/////////////////////////////////////////////////////////

// PointerDevice.cpp : implementation file
//
#include "stdafx.h"
#include "PointerDevice.h"
#include "math.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// PointerDevice

/////////////////////////////////////////////////////////////////////////////////////////
//函数名:PointerDevice(CWnd *parent)
//输入参数:父窗口的指针
//返回值:无
//作用:为PointerDevice类的构造函数,将类的内部变量设置成默认值,创建类的实例并显示子窗体
PointerDevice::PointerDevice(CWnd *parent)
{
	PD_Width = 200;			//仪表默认宽度
	PD_Height = 200;		//仪表默认高度

	//设置仪表的原点为窗体的中心
	PD_Origin.x = (long)((PD_Width - 1) / 2);		
	PD_Origin.y = (long)((PD_Height - 1) / 2);

	PD_Direction = 1;		//默认为逆时针转动,该变量表示正方向
	PD_CurrentDirection = 1;//默认方向和正向一样

	PD_UseBitmap = 0;		//默认下仪表不使用位图作为背景。
	PD_BitmapID = 0;		//仪表背景位图的资源ID,默认下不使用

	PD_CenterAngle = 90;	//设置表盘的弧度中心默认位置为Y轴(90度)方向
	PD_SweepAngle = 360;	//设置表盘弧度的默认跨度为360度
	PD_FaceSweepAngle = 360;//设置表盘面板弧度跨度
	PD_TextStartAngle = 0;	//刻度文字的起始位置默认为弧度中心位置
	
	PD_SmallGridLength = 4;	//设置表盘小刻度线长度
	PD_SmallGridNum = 50;	//设置表盘默认小刻度格数
	PD_BigGridLength = 8;	//设置表盘大刻度线长度为
	PD_BigGridNum = 10;		//设置表盘默认大刻度格数

	PD_FontSize = 12;		//刻度标注字体大小,默认采用12点字体
	PD_OutputFontSize = 16;	//输出框内文字大小,默认采用16点字体

	PD_Title = "";			//标题文字(默认为空)
	PD_TitleOffset.x = 0;	//标题相对仪表窗口左上角的位置	
	PD_TitleOffset.y = 0;
	PD_TitleColor = RGB(0, 0, 0);	//默认的标题颜色
	PD_TitleFontSize = 0;	//标题栏字体大小(默认为0,表示不需要标题)

	PD_TextSpace = 10;		//默认文字与刻度线距离
	PD_CenterNumber = 0;	//默认刻度中心的数字为0
	PD_DeltaNumber = 1;		//默认刻度数字增量为1

	PD_BorderWidth = 12;		//圆形边界的宽度

	PD_StepLength = 5;		//指针默认的最小旋转量
	
	PD_FaceRadius = (UINT)((PD_Width - 1) / 2) - PD_BorderWidth;	//设置表盘弧度的默认半径为仪表边长的一半(扣除边界尺寸)
	PD_Radius = PD_FaceRadius - 10;		//默认情况下,让刻度显离开边缘10个象素
	PD_InnerRadius = 0;	//默认情况不加空心内圆
	PD_AxleRadius = 0;	//指针转轴的半径

	PD_PointerWidth = 1;	//默认表针为1象素粗

	PD_PointerLength = PD_Radius - PD_BigGridLength - 1;	//默认的指针长度

	PD_HasPointerShadow = 0;	//默认没有指针阴影
	PD_PointerShadowColor = RGB(100, 100, 100);	//默认的指针阴影颜色
	PD_PointerShadowOffset.x = 3;	//指针阴影相对于指针的偏移量
	PD_PointerShadowOffset.y = 2;
	
	PD_PointerColor = RGB(0, 255, 0);	//默认仪表指针颜色为绿色

	PD_AxleColor = RGB(150, 150, 150);		//默认仪表指针的轴颜色

	PD_BkColor = GetSysColor(COLOR_3DFACE);		//默认仪表背景颜色和对话框背景颜色一致
	PD_CalibrationColor = RGB(255, 255, 255);	//默认仪表刻度颜色为白色
	PD_FaceColor = RGB(0, 0, 0);				//默认仪表表盘颜色为黑色
	PD_TextColor = PD_CalibrationColor;			//默认刻度文字和刻度线颜色相同

	PD_BorderColor = RGB(150, 150, 150);		//定义边界颜色为灰色

	PD_Timer = 30;	//仪表内部定时器的触发时间间隔,默认为40毫秒

	PD_Status = PD_UPDATED;	//仪表的默认状态设置成测试状态

	PD_IsLoop = false;		//默认情况下,仪表的指针不能循环转动

	PD_RotateDir = false;	//默认情况下,仪表的指针是逆时针转动

	PD_CurrentAngle = 0;	//默认情况下,仪表的指针和刻度弧的中线重合

	PD_CurrentNumber = 0;	//设置量程和当前示数
	PD_MaxNumber = 10;
	PD_MinNumber = 0;

	PD_PointerSide.x = 3;	//设置默认的指针形状
	PD_PointerSide.y = 6;
	PD_PointerTail = 10;

	PD_OutputPos.x = 0;		//设置默认的输出框位置
	PD_OutputPos.y = - ((int)PD_Radius / 2) + 5;

	PD_OutputWidth = (PD_Radius / 2);	//设置默认的输出框大小
	PD_OutputHeight = 20;	

	PD_OutputBkColor = RGB(0, 0, 55);	//设置输出框的外观
	PD_OutputBdColor = RGB(255, 255, 255);
	PD_OutputTextColor = RGB(255, 255, 0);	

	PD_OutputTextPos.x = 0;
	PD_OutputTextPos.y = PD_OutputPos.y - PD_OutputFontSize / 2;

	PD_OutputAccuracy = 1;	//默认输出框采用一位小数精度
	PD_Accuracy = 1;		//默认刻度文字用一位小数精度

	PD_Style = PD_3DSTYLE;	//默认采用3D边框

	PD_Update();	//调用该函数对其他变量进行初始化

	//创建相应的静态控件并且显示
	CRect rect;			
	rect.left = rect.top = 0;
	rect.bottom = PD_Height - 1; 
	rect.right = PD_Width - 1;
	Create(NULL, WS_CHILD | WS_VISIBLE | SS_NOTIFY, rect, parent);	

	SetTimer(1, PD_Timer, NULL);	//设置定时器
}

/////////////////////////////////////////////////////////////////////////////////////////
//函数名:~PointerDevice()
//输入参数:无
//返回值:无
//作用:析构函数
PointerDevice::~PointerDevice()
{
	PD_Font.DeleteObject();
	PD_OutputFont.DeleteObject();
	KillTimer(1);
}


BEGIN_MESSAGE_MAP(PointerDevice, CStatic)
	//{{AFX_MSG_MAP(PointerDevice)
	ON_WM_PAINT()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// PointerDevice message handlers


/////////////////////////////////////////////////////////////////////////////////////////
//函数名:OnPaint()
//输入参数:无
//返回值:无
//作用:重载函数,绘制仪表盘的界面
void PointerDevice::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	// TODO: Add your message handler code here
	DrawFace();
	// Do not call CStatic::OnPaint() for painting messages
}


/////////////////////////////////////////////////////////////////////////////////////////
//函数名:OnPaint()
//输入参数:定时器事件的ID
//返回值:无
//作用:重载函数,处理定时器消息,完成指针某时刻的位置指定,更新界面显示
void PointerDevice::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	switch(PD_Status)	//仪表将根据不同的状态作出反应
	{
	case PD_TEST:		//测试状态,转动指针
		PD_CurrentAngle += PD_StepLength * PD_CurrentDirection;
		if(PD_IsLoop == false && (PD_CurrentAngle >= (PD_SweepAngle / 2) || PD_CurrentAngle <= - (PD_SweepAngle / 2)))
		{
			PD_CurrentDirection = - PD_CurrentDirection;
		}
		DrawFace();		//更新显示
		break;
	case PD_UPDATED:	//等候状态,等待数据的变动
		break;
	case PD_UPDATING:	//更新过程状态,指针尚未摆动到合适的位置
		if(PD_CurrentAngle < PD_ObjectAngle)	//当前角度小于目标角度
		{
			PD_CurrentAngle += PD_StepLength * PD_Direction;
			if(PD_CurrentAngle > PD_ObjectAngle)
			{
				PD_CurrentAngle = PD_ObjectAngle;
				PD_Status = PD_UPDATED;
			}
		}
		else	//当前角度大于目标角度
		{
			PD_CurrentAngle -= PD_StepLength * PD_Direction;
			if(PD_CurrentAngle < PD_ObjectAngle)
			{
				PD_CurrentAngle = PD_ObjectAngle;
				PD_Status = PD_UPDATED;
			}
		}
		DrawFace();		//更新显示
		break;
	case PD_SHUTDOWN:	//关闭状态,不作响应
		break;
	default:
		break;
	}
	CStatic::OnTimer(nIDEvent);
}


/////////////////////////////////////////////////////////////////////////////////////////
//函数名:DrawFace()
//输入参数:无
//返回值:无
//作用:绘制整个仪表的界面
void PointerDevice::DrawFace()
{
	CClientDC dc(this);
	CDC dcmem;
	BITMAP bmp;	
	CBitmap bmpc, *pbitmapold;
	CPen pen, *ppenold;	
	CBrush brush0, brush, *pbrushold;
	COLORREF temp_color;

	int j;
	
	if(PD_UseBitmap == 1)	//使用位图背景
		bmpc.LoadBitmap(PD_BitmapID);
	else if(PD_UseBitmap == 2)	//使用映射位图作为背景
		bmpc.LoadMappedBitmap(PD_BitmapID);
	else	//不使用位图背景
		bmpc.CreateCompatibleBitmap(&dc, PD_Width, PD_Height);	//创建与系统兼容的位图

	bmpc.GetBitmap(&bmp);
	
	if(!PD_Font.m_hObject)
		PD_Font.CreateFont(PD_FontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF_SWISS, _T("Arial"));	//创建一个默认的刻度数字字体
	if(!PD_OutputFont.m_hObject)
		PD_OutputFont.CreateFont(PD_OutputFontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF_SWISS, _T("Arial"));	//创建一个默认的刻度数字字体
	if(!PD_TitleFont.m_hObject)
		PD_TitleFont.CreateFont(PD_TitleFontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF_SWISS, _T("Arial"));	//创建一个默认的刻度数字字体

	dcmem.CreateCompatibleDC(&dc);
	pbitmapold = (CBitmap *)dcmem.SelectObject(&bmpc);

	if(PD_UseBitmap != 1 && PD_UseBitmap != 2)	//如果不使用位图或者映射位图作为背景,就用矢量绘制整个面板
	{	
		//绘制“透明”的位图底色
		brush0.CreateSolidBrush(PD_BkColor);
		CBrush * pbrushold = (CBrush *)dcmem.SelectObject(&brush0);
		dcmem.SelectStockObject(NULL_PEN);
		dcmem.Rectangle(0, 0, bmp.bmWidth + 1, bmp.bmHeight + 1);
		dcmem.SelectObject(pbrushold);

		//绘制3D圆形外框
		temp_color = PD_BorderColor;
		brush.CreateSolidBrush(PD_BorderColor);
		pbrushold = (CBrush *)dcmem.SelectObject(&brush);
		dcmem.Pie(PD_Origin.x - PD_FaceRadius - PD_BorderWidth, PD_Origin.y - PD_FaceRadius - PD_BorderWidth, PD_Origin.x + PD_FaceRadius + PD_BorderWidth, PD_Origin.y + PD_FaceRadius + PD_BorderWidth, PD_FaceStartPoint.x, PD_FaceStartPoint.y, PD_FaceEndPoint.x, PD_FaceEndPoint.y);
		dcmem.SelectObject(pbrushold);
		brush.DeleteObject();
		if(PD_BorderWidth)
		{
			int halfbdw = (int)(PD_BorderWidth / 2);
			for(j = 0; j < (int)PD_BorderWidth; j ++)
			{
				if(j >= halfbdw)
					temp_color = GetNextColor(temp_color, 0.9);
				else
					temp_color = GetNextColor(temp_color, 1.1);

				pen.CreatePen(PS_SOLID, 1, temp_color);
				ppenold = (CPen *)dcmem.SelectObject(&pen);

				dcmem.MoveTo(PD_FaceStartPoint);
				dcmem.AngleArc(PD_Origin.x, PD_Origin.y, PD_FaceRadius + j, (float)(PD_RightAngle - (PD_FaceSweepAngle - PD_SweepAngle)/ 2), (float)PD_FaceSweepAngle);	//绘制刻度弧
				dcmem.SelectObject(ppenold);
				pen.DeleteObject();
			}
		}

		//绘制扇形(圆形)刻度盘
		brush.CreateSolidBrush(PD_FaceColor);
		pbrushold = (CBrush *)dcmem.SelectObject(&brush);
		pen.CreatePen(PS_SOLID, 1, PD_FaceColor);
		ppenold = (CPen *)dcmem.SelectObject(&pen);
		dcmem.Pie(PD_Origin.x - PD_FaceRadius, PD_Origin.y - PD_FaceRadius, PD_Origin.x + PD_FaceRadius, PD_Origin.y + PD_FaceRadius, PD_FaceStartPoint.x, PD_FaceStartPoint.y, PD_FaceEndPoint.x, PD_FaceEndPoint.y);
		dcmem.SelectObject(pbrushold);
		brush.DeleteObject();
		dcmem.SelectObject(ppenold);
		pen.DeleteObject();

		//绘制内圆
		if(PD_InnerRadius)
		{
			pbrushold = (CBrush *)dcmem.SelectObject(&brush0);
			dcmem.Ellipse(PD_Origin.x - PD_InnerRadius, PD_Origin.y - PD_InnerRadius, PD_Origin.x + PD_InnerRadius, PD_Origin.y + PD_InnerRadius);
			dcmem.SelectObject(pbrushold);
		}
		brush0.DeleteObject();
	}

	pen.CreatePen(PS_SOLID, 1, PD_CalibrationColor);
	ppenold = (CPen *)dcmem.SelectObject(&pen);
	
	//绘制刻度弧线,这里先暂时不用
	//dcmem.MoveTo(PD_StartPoint.x, PD_StartPoint.y);
	//dcmem.AngleArc(PD_Origin.x, PD_Origin.y, PD_Radius, PD_RightAngle, PD_SweepAngle);	//绘制刻度弧
	
	//绘制大刻度分割线
	UINT i;
	UINT R1 = PD_Radius - PD_BigGridLength; 
	double delta = PD_SweepAngle / PD_BigGridNum;
	double current_angle = PD_RightAngle;
	CPoint in, out;
	for(i = 0; i < PD_BigGridNum; i ++)	
	{
		out.x = PD_Origin.x + (long)(PD_Radius * cos(ANG * current_angle));
		out.y = PD_Origin.y - (long)(PD_Radius * sin(ANG * current_angle));
		in.x = PD_Origin.x + (long)(R1 * cos(ANG * current_angle));
		in.y = PD_Origin.y - (long)(R1 * sin(ANG * current_angle));
		dcmem.MoveTo(in);
		dcmem.LineTo(out);
		current_angle += delta;
	}

	
	//绘制小刻度分割线
	R1 = PD_Radius - PD_SmallGridLength;
	delta = PD_SweepAngle / PD_SmallGridNum;
	current_angle = PD_RightAngle;
	int tmp = PD_SmallGridNum / PD_BigGridNum;
	for(i = 0; i < PD_SmallGridNum; i ++)	
	{
		if(i % tmp == 0)
		{
			current_angle += delta;
			continue;
		}
		out.x = PD_Origin.x + (long)(PD_Radius * cos(ANG * current_angle));
		out.y = PD_Origin.y - (long)(PD_Radius * sin(ANG * current_angle));
		in.x = PD_Origin.x + (long)(R1 * cos(ANG * current_angle));
		in.y = PD_Origin.y - (long)(R1 * sin(ANG * current_angle));
		dcmem.MoveTo(in);
		dcmem.LineTo(out);
		current_angle += delta;
	}
  	dcmem.SelectObject(ppenold);
	pen.DeleteObject();	 


	//写入刻度文字
	R1 = PD_Radius - ((PD_BigGridLength > PD_SmallGridLength) ? PD_BigGridLength : PD_SmallGridLength);
	CFont * pfontold = (CFont *)dcmem.SelectObject(&PD_Font);
	int oldmode = dcmem.SetBkMode(TRANSPARENT);
	COLORREF oldcolor = dcmem.SetTextColor(PD_TextColor);
	CString text, format;
	CPoint textpos;
	double tmpnum;
	current_angle = PD_TextStartAngle + PD_CenterAngle;
	delta = PD_SweepAngle / PD_BigGridNum;
	for(i = 0; i <= PD_BigGridNum; i ++)	
	{
		textpos.x = PD_Origin.x + (long)((R1 - PD_TextSpace) * cos(ANG * current_angle));
		textpos.y = PD_Origin.y - (long)((R1 - PD_TextSpace) * sin(ANG * current_angle));
		tmpnum = PD_CenterNumber + i * PD_DeltaNumber;
		if((int)tmpnum == tmpnum)
		{
			text.Format("%d", (int)tmpnum); 
		}
		else
		{
			format.Format("%%.%dlf", PD_OutputAccuracy);
			text.Format(format, tmpnum); 
		}
		if(current_angle < 180 && current_angle > 0)
		{
			dcmem.SetTextAlign(TA_CENTER | TA_TOP);
			dcmem.TextOut(textpos.x + 2, textpos.y - 5, text);
		}
		else
		{
			dcmem.SetTextAlign(TA_CENTER | TA_BOTTOM);
			dcmem.TextOut(textpos.x + 2, textpos.y + 5, text);
		}
		current_angle += delta;
		if(current_angle - PD_TextStartAngle - PD_CenterAngle >= 360)
			break;
		if(PD_SweepAngle < 360 && current_angle >= PD_LeftAngle)
			break;
	}

	current_angle = PD_TextStartAngle + PD_CenterAngle;
	if(PD_SweepAngle < 360)	//对于非圆形的表盘,还要画出负数部分
	{
		for(i = 0; i <= PD_BigGridNum; i ++)	
		{
			textpos.x = PD_Origin.x + (long)((R1 - PD_TextSpace) * cos(ANG * current_angle));
			textpos.y = PD_Origin.y - (long)((R1 - PD_TextSpace) * sin(ANG * current_angle));
			tmpnum = PD_CenterNumber - i * PD_DeltaNumber;
			if((int)tmpnum == tmpnum)
			{
				text.Format("%d", (int)tmpnum); 
			}
			else
			{

⌨️ 快捷键说明

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