📄 rudderdevice.cpp
字号:
/////////////////////////////////////////////////////////
// 舵型指示设备RudderDevice封装类
// 版本:1.05
// 最后修改日期:2002.1.25
/////////////////////////////////////////////////////////
// RudderDevice.cpp : implementation file
//
#include "stdafx.h"
#include "RudderDevice.h"
#include "math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// RudderDevice
/////////////////////////////////////////////////////////////////////////////////////////
//函数名:RudderDevice(CWnd * parent)
//输入参数:父窗口的指针
//返回值:无
//作用:构造函数,初始化变量的值,创建并显示对象
RudderDevice::RudderDevice(CWnd * parent)
{
RD_Width = 120; //默认的仪表宽度
RD_Height = 120; //默认的仪表高度
RD_Origin.x = (RD_Width - 1) / 2; //默认的原点是仪表窗口的中心
RD_Origin.y = (RD_Height - 1) / 2;
RD_AxleLength = (RD_Height - 1) / 2; //默认的摆动轴长度为窗口高度的一半
RD_AxleRadius = 8; //默认的摆动轴截面半径
RD_FrameThick = 20; //滑槽边框的厚度
RD_FrameRadius = 60; //滑槽拱形边框的半径
RD_MinLevel = 0; //仪表内的最低档位
RD_MaxLevel = 8; //仪表内的最高档位
RD_CurrentLevel = 2; //仪表的当前档位
RD_ObjectLevel = RD_CurrentLevel; //仪表的目标档位
RD_SweepAngle = 180; //摆动轴的摆动幅度,采用角度值
RD_CurrentAngle = 0; //摆动轴的当前夹角,相对于Z轴正向,采用角度值
RD_BkColor = GetSysColor(COLOR_3DFACE); //默认的仪表背景色
RD_Color = RGB(240, 240, 240); //默认的仪表颜色
RD_LampLightColor = RGB(255, 0, 0); //默认的指示灯颜色
RD_LampDarkColor = RGB(55, 0, 0);
RD_TextLightColor = RGB(0, 0, 255); //默认的文字颜色
RD_TextDarkColor= RGB(0, 0, 0);
RD_LampWidth = 40; //指示灯的尺寸
RD_LampHeight = 4;
RD_LampOffset.x = -20; //默认的指示灯位置(相对于原点)
RD_LampOffset.y = RD_FrameRadius - 5;
RD_TextOffset.x = 10; //默认的文字相对于指示灯的偏移位置
RD_TextOffset.y = - 7;
RD_TextLeft = "档0,档1,档2,档3,档4,档5,档6,档7,档8"; //默认的标注文字
RD_TextRight = "0节,1节,2节,3节,4节,5节,6节,7节,8节"; //默认的标注文字
RD_RotateDirection = 1; //默认的旋转方向是向上(正)
RD_Status = RD_UPDATED; //仪表默认的当前状态
RD_HasAxle = 0; //默认没有摆动轴
RD_FontSize = 14;
RD_Update(); //调用该函数对其他变量初始化
//创建相应的静态控件并且显示
CRect rect;
rect.left = rect.top = 0;
rect.bottom = RD_Height - 1;
rect.right = RD_Width - 1;
Create(NULL, WS_CHILD | WS_VISIBLE | SS_NOTIFY, rect, parent);
SetTimer(1, 50, NULL); //设置工作时使用的计时器
}
RudderDevice::~RudderDevice()
{
RD_Font.DeleteObject();
KillTimer(1);
}
BEGIN_MESSAGE_MAP(RudderDevice, CStatic)
//{{AFX_MSG_MAP(RudderDevice)
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// RudderDevice message handlers
/////////////////////////////////////////////////////////////////////////////////////////
//函数名:OnPaint()
//输入参数:无
//返回值:无
//作用:重载函数,绘制仪表界面
void RudderDevice::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
DrawFace();
// Do not call CStatic::OnPaint() for painting messages
}
/////////////////////////////////////////////////////////////////////////////////////////
//函数名:DrawFace()
//输入参数:无
//返回值:无
//作用:绘制仪表界面
void RudderDevice::DrawFace()
{
int i;
CClientDC dc(this);
CDC dcmem;
dcmem.CreateCompatibleDC(&dc);
CBitmap bmpc;
bmpc.CreateCompatibleBitmap(&dc, RD_Width, RD_Height); //创建与系统兼容的位图
BITMAP bmp;
bmpc.GetBitmap(&bmp);
CBrush brush, *pbrushold;
CPen pen, *ppenold;
CFont *pfontold;
COLORREF temp_color;
if(!RD_Font.m_hObject)
RD_Font.CreateFont(RD_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")); //创建一个默认的刻度数字字体
brush.CreateSolidBrush(RD_BkColor);
//绘制仪表的背景色
CBitmap * pbitmapold = (CBitmap *)dcmem.SelectObject(&bmpc);
pbrushold = (CBrush *)dcmem.SelectObject(&brush);
dcmem.SelectStockObject(NULL_PEN);
dcmem.Rectangle(0, 0, bmp.bmWidth + 1, bmp.bmHeight + 1);
dcmem.SelectObject(pbrushold);
brush.DeleteObject();
//绘制拱形的滑槽
temp_color = GetNextColor(RD_Color, 0.1);
UINT maxcolor = GetRValue(temp_color);
if(maxcolor < GetGValue(temp_color))
maxcolor = GetGValue(temp_color);
if(maxcolor < GetBValue(temp_color))
maxcolor = GetBValue(temp_color);
int h = (UINT)(RD_FrameRadius / maxcolor);
if(h == 0)
h = 1;
int lt, rb;
for(i = 0; i < (int)RD_FrameRadius; i ++)
{
brush.CreateSolidBrush(temp_color);
pbrushold = (CBrush *)dcmem.SelectObject(&brush);
lt = RD_Origin.y - RD_FrameRadius + i * h;
rb = RD_Origin.y + RD_FrameRadius - i * h;
if(lt > RD_Origin.y)
lt = RD_Origin.y;
if(rb < RD_Origin.y)
rb= RD_Origin.y;
dcmem.Rectangle(RD_Origin.x - RD_AxleRadius - RD_FrameThick, lt, RD_Origin.x + RD_AxleRadius + RD_FrameThick, rb);
dcmem.SelectObject(pbrushold);
brush.DeleteObject();
temp_color = GetNextColor(temp_color, 1.1);
}
if(RD_HasAxle) //如果有摆动轴,绘制黑色的滑槽内孔
{
dcmem.SelectStockObject(BLACK_BRUSH);
dcmem.Rectangle(RD_Origin.x - RD_AxleRadius - 1, RD_Origin.y - RD_FrameRadius + 2, RD_Origin.x + RD_AxleRadius + 1, RD_Origin.y + RD_FrameRadius - 2);
}
//绘制档位指示灯以及文字
int oldmode = dcmem.SetBkMode(TRANSPARENT);
int index;
CString text, allleft = RD_TextLeft, allright = RD_TextRight;
pfontold = dcmem.SelectObject(&RD_Font);
int space = RD_LampHeight + (2 * RD_FrameRadius - RD_SweepLevel * RD_LampHeight) / (RD_SweepLevel - 1) - 1;
for(i = 0; i < (int)RD_SweepLevel; i ++)
{
if(i == (int)(RD_CurrentLevel - RD_MinLevel))
{
brush.CreateSolidBrush(RD_LampLightColor);
dcmem.SetTextColor(RD_TextLightColor);
}
else
{
brush.CreateSolidBrush(RD_LampDarkColor);
dcmem.SetTextColor(RD_TextDarkColor);
}
pbrushold = (CBrush *)dcmem.SelectObject(&brush);
//绘制指示灯
if(RD_HasAxle) //有摆动轴,指示灯分列两边
{
dcmem.Rectangle(RD_Origin.x + RD_LampOffset.x, - i * space + RD_Origin.y + RD_LampOffset.y, RD_Origin.x + RD_LampOffset.x + RD_LampWidth, - i * space + RD_Origin.y + RD_LampOffset.y + RD_LampHeight);
dcmem.Rectangle(RD_Origin.x - RD_LampOffset.x, - i * space + RD_Origin.y + RD_LampOffset.y, RD_Origin.x - RD_LampOffset.x - RD_LampWidth, - i * space + RD_Origin.y + RD_LampOffset.y + RD_LampHeight);
}
else //没有摆动轴,绘制单列绘制指示灯
{
dcmem.Rectangle(RD_Origin.x + RD_LampOffset.x, - i * space + RD_Origin.y + RD_LampOffset.y, RD_Origin.x + RD_LampOffset.x + RD_LampWidth, - i * space + RD_Origin.y + RD_LampOffset.y + RD_LampHeight);
}
//绘制左边的标注文字
index = allleft.Find(",");
if(index != -1)
text = allleft.Left(index);
else
text = allleft;
allleft = allleft.Right(allleft.GetLength() - text.GetLength() - 1);
dcmem.SetTextAlign(TA_RIGHT | TA_TOP);
dcmem.TextOut(RD_Origin.x - RD_LampOffset.x - RD_LampWidth - RD_TextOffset.x, - i * space + RD_Origin.y + RD_LampOffset.y + RD_TextOffset.y, text);
//绘制右边的标注文字
index = allright.Find(",");
if(index != -1)
text = allright.Left(index);
else
text = allright;
allright = allright.Right(allright.GetLength() - text.GetLength() - 1);
dcmem.SetTextAlign(TA_LEFT | TA_TOP);
dcmem.TextOut(RD_Origin.x + RD_LampOffset.x + RD_LampWidth + RD_TextOffset.x, - i * space + RD_Origin.y + RD_LampOffset.y + RD_TextOffset.y, text);
dcmem.SelectObject(pbrushold);
brush.DeleteObject();
}
dcmem.SetBkMode(oldmode);
dcmem.SelectObject(pfontold);
RD_Font.DeleteObject();
//计算轴体的一些关键参数
if(RD_HasAxle)
{
int len, shortaxle;
shortaxle = (int)(RD_AxleRadius * cos(ANG * RD_CurrentAngle));
RD_AxleCenter.y = RD_Origin.y - (long)(RD_AxleLength * sin(ANG * RD_CurrentAngle)); //摆动轴的y位置
//绘制摆动轴的轴体
temp_color = RD_Color;
for(i = 0; i < (int)RD_AxleRadius; i ++)
{
len = (int)(sqrt(RD_AxleRadius * RD_AxleRadius - i * i) * cos(ANG * RD_CurrentAngle) - 1);
if(RD_CurrentAngle < 0)
len = - len;
pen.CreatePen(PS_SOLID, 1, temp_color);
ppenold = (CPen *)dcmem.SelectObject(&pen);
dcmem.MoveTo(RD_AxleCenter.x + i - 1, RD_AxleCenter.y);
dcmem.LineTo(RD_Origin.x + i - 1, RD_Origin.y + len);
dcmem.MoveTo(RD_AxleCenter.x - i - 1, RD_AxleCenter.y);
dcmem.LineTo(RD_Origin.x - i - 1, RD_Origin.y + len);
dcmem.SelectObject(ppenold);
pen.DeleteObject();
temp_color = GetNextColor(temp_color, 0.9);
}
//绘制摆动轴截面的椭圆
temp_color = GetNextColor(RD_Color, 0.6);
brush.CreateSolidBrush(temp_color);
pbrushold = (CBrush *)dcmem.SelectObject(&brush);
dcmem.Ellipse(RD_AxleCenter.x - RD_AxleRadius, RD_AxleCenter.y - shortaxle, RD_AxleCenter.x + RD_AxleRadius, RD_AxleCenter.y + shortaxle);
dcmem.SelectObject(pbrushold);
brush.DeleteObject();
} //摆动轴绘制结束
//将内存DC的内容一次画在屏幕DC上
dc.BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &dcmem, 0, 0, SRCCOPY);
dcmem.SelectObject(pbitmapold);
bmpc.DeleteObject();
dcmem.DeleteDC();
}
/////////////////////////////////////////////////////////////////////////////////////////
//函数名:RD_MoveWindow(int x, int y)
//输入参数:仪表窗口左上角的目标位置坐标
//返回值:无
//作用:移动仪表窗口
void RudderDevice::RD_MoveWindow(int x, int y)
{
CRect rect;
GetWindowRect(&rect);
MoveWindow(x, y, rect.Width(), rect.Height(), true);
}
/////////////////////////////////////////////////////////////////////////////////////////
//函数名:RD_Update()
//输入参数:无
//返回值:无
//作用:该函数对其他不能用函数设置的变量进行设置,应该在其他变量设置完全后再最后调用
void RudderDevice::RD_Update()
{
RD_SweepLevel = RD_MaxLevel - RD_MinLevel + 1; //仪表的档位总数
RD_AnglePerLevel = RD_SweepAngle / (RD_SweepLevel - 1); //每档之间变化的角度值
RD_AxleCenter.x = RD_Origin.x; //摆动轴的x位置和仪表原点相同
RD_AxleCenter.y = RD_Origin.y - (long)(RD_AxleLength * sin(ANG * RD_CurrentAngle)); //摆动轴的y位置
RD_CurrentAngle = RD_SweepAngle / 2 - (RD_MaxLevel - RD_CurrentLevel) * RD_AnglePerLevel;
}
/////////////////////////////////////////////////////////////////////////////////////////
//函数名:OnTimer(UINT nIDEvent)
//输入参数:定时器触发事件的ID
//返回值:无
//作用:重载函数,负责对自检状态和工作状态下仪表的显示更新
void RudderDevice::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(RD_Status)
{
case RD_TEST:
if(RD_CurrentLevel >= RD_MaxLevel || RD_CurrentLevel <= RD_MinLevel)
RD_RotateDirection = - RD_RotateDirection;
RD_CurrentAngle += RD_AnglePerLevel * RD_RotateDirection;
RD_CurrentLevel += RD_RotateDirection;
DrawFace();
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -