在做测控类的嵌入式系统开发时,一个精美的上位机控制软件UI是可以为系统增色不少,一般会采用组态软件来开发,我们来看看下面的界面
是不是非常直观有工业质感,还可以根据实时数据进行动态的显示和动画效果,那这些炫酷的界面是怎么实现的呢,我们来探讨一下相关技术。
首先我们看到的漂亮精美的画面是一幅一幅的png图片或者gif动图,如果我们能找到方法将这些图片根据状态或采集数据和状态的需要,实时的展示渲染出来是不是就可以了呢。
渲染技术其实从图像系统出来就一直在进化,游戏是这方面的优秀应用场景,可以用gdi gdiplus opengl vuklan webgpu等技术实现多平台,甚至跨平台的UI
下面是一组工业风的开关,可以用双缓冲的gdi plus方式结合鼠标的操作事件进行切换显示就可以实现形象的工业控制开关
下面就是一个switcherctl的类实现,可以嵌入到你的代码中实现工业开关控制
// SwitcherCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "VDC300Controler.h"
#include "SwitcherCtrl.h"
#include "DrawFunction.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CSwitcherCtrl
CSwitcherCtrl::CSwitcherCtrl()
{
}
CSwitcherCtrl::~CSwitcherCtrl()
{
}
BEGIN_MESSAGE_MAP(CSwitcherCtrl, CWnd)
//{{AFX_MSG_MAP(CSwitcherCtrl)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CSwitcherCtrl message handlers
BOOL CSwitcherCtrl::Create(DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID)
{
BOOL result ;
static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW) ;
result = CWnd::CreateEx(NULL,
className, NULL, dwStyle,
rect.left, rect.top, rect.right-rect.left+45, rect.bottom-rect.top+30,
pParentWnd->GetSafeHwnd(), (HMENU)nID) ;
if (result != 0)
{
/*
hFuncInst = LoadLibrary("User32.DLL");
BOOL bRet=FALSE;
if(hFuncInst)
UpdateLayeredWindow=(MYFUNC)GetProcAddress(hFuncInst, "UpdateLayeredWindow");
else
{
AfxMessageBox("User32.dll ERROR!");
exit(0);
}
*/
//初始化gdiplus的环境
// Initialize GDI+.
m_Blend.BlendOp=0; //theonlyBlendOpdefinedinWindows2000
m_Blend.BlendFlags=0; //nothingelseisspecial...
m_Blend.AlphaFormat=1; //...
m_Blend.SourceConstantAlpha=255;//AC_SRC_ALPHA
//CDC *pDC;
//pDC = GetDC();
//DrawLed(pDC,m_nLedColor,m_nLedMode,m_nLedShape,"LED");
}
return result;
}
void CSwitcherCtrl::DrawSwitcher(int Transparent)
{
HDC hdcTemp=GetDC()->m_hDC;
if(Transparent<0||Transparent>100) Transparent=100;
m_Blend.SourceConstantAlpha=int(Transparent*2.55);//1~255
RECT rct;
GetClientRect(&rct);
Graphics graph(hdcTemp);//m_hdcMemory);
ImageFromIDResource(IDR_PNGSWITCHER,"PNG",m_pImageSwitcher);
if(m_pImageSwitcher)
{
m_SwitchWidth =m_pImageSwitcher->GetWidth();
m_SwitchHeight =m_pImageSwitcher->GetHeight();
}
else
return ;
m_bSwitcherOn?graph.DrawImage(m_pImageSwitcher,0, 0, 0, 5,m_SwitchWidth/2,m_SwitchHeight-10,UnitPixel):
graph.DrawImage(m_pImageSwitcher,0, 0, m_SwitchWidth/2, 5,m_SwitchWidth/2,m_SwitchHeight-10,UnitPixel);
CString strcaption;
strcaption.Format("%s-%s",m_strCaption,m_bSwitcherOn?"ON":"OFF");
int nLen = strlen(strcaption) + 1;
int nwLen = MultiByteToWideChar(CP_ACP, 0, strcaption, nLen, NULL, 0);
unsigned short lpszTitle[256];
MultiByteToWideChar(CP_ACP, 0, strcaption, nLen, lpszTitle, nwLen);
FontFamily fontsmallFamily(L"宋体");//选择一种字体
Gdiplus::Font fontSmall(&fontsmallFamily,12,FontStyleRegular);
int titlestarty=rct.bottom-20;
int titlestartx=rct.left;
if(m_bSwitcherOn)
{
graph.DrawString(lpszTitle,-1,&fontSmall,PointF(titlestartx,titlestarty),&SolidBrush(Color::Black));
graph.DrawString(lpszTitle,-1,&fontSmall,PointF(titlestartx-2,titlestarty-2),&SolidBrush(Color::Red));
}
else
{
graph.DrawString(lpszTitle,-1,&fontSmall,PointF(titlestartx,titlestarty),&SolidBrush(Color::Black));
graph.DrawString(lpszTitle,-1,&fontSmall,PointF(titlestartx-2,titlestarty-2),&SolidBrush(Color::White));
}
delete(m_pImageSwitcher);
m_pImageSwitcher=NULL;
::ReleaseDC(m_hWnd,hdcTemp);
hdcTemp=NULL;
}
/*
BOOL CSwitcherCtrl::ImageFromIDResource(UINT nID, LPCTSTR sTR,Image * &pImg)
{
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // type
if (!hRsrc)
return FALSE;
// load resource into memory
DWORD len = SizeofResource(hInst, hRsrc);
BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
if (!lpRsrc)
return FALSE;
// Allocate global memory on which to create stream
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
memcpy(pmem,lpRsrc,len);
IStream* pstm;
CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
// load from stream
pImg=Gdiplus::Image::FromStream(pstm);
// free/release stuff
GlobalUnlock(m_hMem);
pstm->Release();
FreeResource(lpRsrc);
return TRUE;
}
*/
void CSwitcherCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(&rect);
// dc.FillSolidRect(rect,RGB(129,129,129));
PaintBK(&dc);
DrawSwitcher();
// Do not call CWnd::OnPaint() for painting messages
}
void CSwitcherCtrl::SetSwitcher(LPCSTR strswitchname, BOOL bOn,int id,HWND hwnd)
{
m_ParentWnd=hwnd;
m_strCaption=strswitchname;
m_bSwitcherOn=bOn;
//m_SwichterCallBck=CallBck;
m_ID=id;
}
void CSwitcherCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bSwitcherOn=1-m_bSwitcherOn;
::SendMessage(m_ParentWnd,WM_DIGOUT_SWITCH,WPARAM(m_ID),LPARAM(m_bSwitcherOn));
//if(m_SwichterCallBck!=NULL)
// m_SwichterCallBck(m_ID,m_bSwitcherOn);
//SendMessage(
Invalidate(FALSE);
CWnd::OnLButtonDown(nFlags, point);
}
void CSwitcherCtrl::SetBkGnd(CDC *pDC)
{
CRect rect, rectS;
CBitmap bmp, *pOldBitmap;
GetClientRect(rect);
GetWindowRect(rectS);
GetParent()->ScreenToClient(rectS);
m_dcBk.DeleteDC();
m_dcBk.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
if(bmp.GetSafeHandle()!=NULL)
{
pOldBitmap = m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rectS.left, rectS.top, SRCCOPY);
bmp.DeleteObject();
}
}
void CSwitcherCtrl::PaintBK(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
}
速度表盘
同上,速度表盘或者压力表盘也可以照此方式实现,将图片作为背景图,然后自绘表指针,根据实时数据计算算出表针的旋转角度,即可实现一组精美的表盘控件。
// DashBoard.cpp : implementation file
//
#include "stdafx.h"
#include "VDC300Controler.h"
#include "DashBoard.h"
#include "Drawfunction.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CDashBoard
CDashBoard::CDashBoard()
{
m_DashBoardName=_T("Km/h");
m_speedvalue=128;
m_dMinValue = 0.00f; //表量程初始值
m_dMaxValue = 140.00f; //表量程终值
m_nTicks = 7; //大格个数
m_nSubTicks = 5; //大格中小格个数
}
CDashBoard::~CDashBoard()
{
if(m_pDashBoard!=NULL)
{
delete(m_pDashBoard);
m_pDashBoard=NULL;
}
}
BEGIN_MESSAGE_MAP(CDashBoard, CWnd)
//{{AFX_MSG_MAP(CDashBoard)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CDashBoard message handlers
BOOL CDashBoard::Create(DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID)
{
BOOL result ;
static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW) ;
result = CWnd::CreateEx(NULL,
className, NULL, dwStyle,
rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID) ;
/*
BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL);
*/
if (result != 0)
{
ImageFromIDResource(IDR_DASHBOARD,"PNG",m_pDashBoard);
ImageFromIDResource(IDR_PNGNUM,"PNG",m_pImageNum);
}
return result;
}
void CDashBoard::DrawDashBoard()
{
CRect rect;
HDC hdcTemp=GetDC()->m_hDC;
GetClientRect(&rect);
Bitmap *m_pBackBmp = ::new Bitmap((HBITMAP)::GetCurrentObject(m_dcBk.m_hDC, OBJ_BITMAP),NULL);
Graphics CacheGraphics(m_pBackBmp );
int nLen = strlen(m_DashBoardName) + 1;
int nwLen = MultiByteToWideChar(CP_ACP, 0, m_DashBoardName, nLen, NULL, 0);
unsigned short lpszTitle[256];
MultiByteToWideChar(CP_ACP, 0, m_DashBoardName, nLen, lpszTitle, nwLen);
FontFamily fontsmallFamily(L"宋体");//选择一种字体
Gdiplus::Font fontSmall(&fontsmallFamily,12,FontStyleRegular);
LOGFONTA lf;
fontSmall.GetLogFontA(&CacheGraphics,&lf);
int fontsmallWidth=abs(lf.lfHeight);
int xblank=(rect.Width()-300)/2;
int yblank=(rect.Height()-300)/2;
CacheGraphics.DrawImage(m_pDashBoard, Rect(xblank,
yblank,
300,//rect.right-xblank,
300));//rect.bottom-yblank));
int midx=rect.Width()/2;
int midy=rect.Height()/2;
DrawScale(&CacheGraphics,CRect(xblank,
yblank,
256,//rect.right-xblank,
256),midx,midy);
int titlestarty=rect.bottom-yblank-60;//rect.bottom-20;
int titlestartx=midx-18; //if(titlestartx<0) titlestartx=0;
CacheGraphics.DrawString(lpszTitle,-1,&fontSmall,PointF(titlestartx,titlestarty),&SolidBrush(Color::Black));
CacheGraphics.DrawString(lpszTitle,-1,&fontSmall,PointF(titlestartx-1,titlestarty-1),&SolidBrush(Color::White));
int ThirdNum=(((int)m_speedvalue)%10);
int SecondNum=(((int)m_speedvalue-ThirdNum)%100)/10;
int FirstNum=(((int)m_speedvalue-SecondNum*10-ThirdNum)%1000)/100;
int FourthNum=(int(m_speedvalue-FirstNum*100-SecondNum*10-ThirdNum)*10);
SolidBrush brush1( Gdiplus::Color( 250, 0,0,0 ) ); //半透明红色
int char_xdis=12;
int char_width=10;
int char_height=16;
int numstartx=midx-2*(char_xdis)-6;
int recwidth=5*(char_xdis);
int recheight=char_height+2;
int numstarty=midy+3*char_height;//(rect.right-rect.left-fontsmallWidth*(nLen-1)/2)/2; if(titlestartx<0) titlestartx=0;
CacheGraphics.FillRectangle(&brush1,Gdiplus::Rect(numstartx-2,numstarty-2,recwidth,recheight));
CacheGraphics.DrawImage(m_pImageNum,Rect(numstartx,numstarty,char_width,char_height), 14*FirstNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,Rect(numstartx+char_xdis,numstarty,char_width,char_height), 14*SecondNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,Rect(numstartx+char_xdis*2,numstarty,char_width,char_height), 14*ThirdNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,Rect(numstartx+char_xdis*3,numstarty,char_width,char_height), 140, 0,14,10,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,Rect(numstartx+char_xdis*4,numstarty,char_width,char_height), 14*FourthNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
/*
CacheGraphics.DrawImage(m_pImageNum,numstartx, numstarty, 14*FirstNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,numstartx+20, numstarty, 14*SecondNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,numstartx+20*2, numstarty, 14*ThirdNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,numstartx+20*3,numstarty+15, 140, 10,14,10,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
CacheGraphics.DrawImage(m_pImageNum,numstartx+20*4, numstarty, 14*FourthNum, 0,14,23,UnitPixel); //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
*/
DrawPitch(&CacheGraphics,CRect(xblank,
yblank,
256,//rect.right-xblank,
256),
midx,midy);
// 对CacheImage进行描画 // ......
// 获得窗口的Graphics对象
Graphics Graphic(hdcTemp);
// 将描画好的CacheImage画到窗口上
Graphic.DrawImage(m_pBackBmp, rect.left,rect.top );
// CacheImage.DeleteObject();
::delete(m_pBackBmp);
m_pBackBmp=NULL;
// delete(m_pDashBoard);
// m_pButtonPng=NULL;
::ReleaseDC(m_hWnd,hdcTemp);
hdcTemp=NULL;
}
void CDashBoard::SetBkGnd(CDC *pDC)
{
CRect rect, rectS;
CBitmap bmp, *pOldBitmap;
GetClientRect(rect);
GetWindowRect(rectS);
GetParent()->ScreenToClient(rectS);
m_dcBk.DeleteDC();
//Gdiplus::Bitmap pBitmap(rcBounds.Width(), rcBounds.Height());
m_dcBk.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rectS.left, rectS.top, SRCCOPY);
bmp.DeleteObject();
Invalidate(FALSE);
}
void CDashBoard::SetSpeedValue(float fspeed)
{
if(fspeed>m_dMaxValue) m_speedvalue=m_dMaxValue;
else m_speedvalue=fspeed;
Invalidate(FALSE);
}
void CDashBoard::OnPaint()
{
CPaintDC dc(this); // device context for painting
DrawDashBoard();
}
void CDashBoard::DrawScale(Graphics *pGraph, CRect rect,int midx,int midy)
{
//画刻度
int nTicks = m_nTicks;
int nSubTicks = m_nSubTicks;
char strFigure[MAXNAMELENGTH + 1];
const int nSidePos = 40;
int nRadius = 0;
if (rect.Width() <= rect.Height())
{
nRadius = rect.Width();
}
else
{
nRadius = rect.Height();
}
memset(strFigure, 0, sizeof(strFigure));
double dRadius = fabs(nRadius / 2 - nRadius / 16);
double dWidth = fabs(nRadius / 14);
double dMaxAngle = double(300.00f / nTicks); //每个大格的角度
double dMinAngle = dMaxAngle / nSubTicks; //每个小格的角度
int center_x=midx;
int center_y=midy;
SolidBrush brush( Gdiplus::Color( 60, 0,0,255 ) ); //半透明红色
pGraph->SetSmoothingMode(SmoothingModeAntiAlias);//平滑处理 抗锯齿
for (int i=0; i<nTicks+1; i++) //刻度坐标
{
Point ptBigScale[4];//ptStartTick, ptStartTick1 ,ptEndTick,ptEndTick1;
double dDrawAngle = (i * dMaxAngle + 30) * PI / 180; //
dDrawAngle-=0.04;
ptBigScale[0].X = int(center_x - dRadius * sin(dDrawAngle));
ptBigScale[0].Y = int(center_y + dRadius * cos(dDrawAngle));
ptBigScale[1].X = int(center_x - dRadius * sin(dDrawAngle) + dWidth * sin(dDrawAngle));
ptBigScale[1].Y = int(center_y + dRadius * cos(dDrawAngle) - dWidth * cos(dDrawAngle));
dDrawAngle += 0.08;//(i * dMaxAngle + 30) * PI / 180; //
ptBigScale[3].X = int(center_x - dRadius * sin(dDrawAngle));
ptBigScale[3].Y = int(center_y + dRadius * cos(dDrawAngle));
ptBigScale[2].X = int(center_x - dRadius * sin(dDrawAngle) + dWidth * sin(dDrawAngle));
ptBigScale[2].Y = int(center_y + dRadius * cos(dDrawAngle) - dWidth * cos(dDrawAngle));
//pGraph->Polygons()
pGraph->FillPolygon(&brush, ptBigScale, 4, FillModeAlternate);
//pGraph->MoveTo(ptStartTick);
//pGraph->LineTo(ptEndTick);
sprintf(strFigure, "%.0f", (m_dMaxValue - m_dMinValue) * i / nTicks);
unsigned short wcharFigure[100];
unsigned short *pshort=&wcharFigure[0];
FontFamily fontsmallFamily(L"黑体");//选择一种字体
Gdiplus::Font fontSmall(&fontsmallFamily,12,FontStyleRegular);
// LOGFONTA lf;
//fontSmall.GetLogFontA(&CacheGraphics,&lf);
Color fontColor(Color::Black);
CharToWChar(strFigure, &pshort);
//pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[0].X-20,ptBigScale[3].Y-5),&SolidBrush(Color::Black));
if (dMaxAngle * (nTicks - i) - 30 < 20)
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[2].X-30,ptBigScale[2].Y-5),&SolidBrush(fontColor));
}
else if (dMaxAngle * (nTicks - i) - 30 < 40)
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[2].X-30,ptBigScale[1].Y),&SolidBrush(Color::Gray));
}
else if (dMaxAngle * (nTicks - i) - 30 < 60)
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-26,ptBigScale[1].Y),&SolidBrush(fontColor));
// pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[0].X-20,ptBigScale[3].Y-5),&SolidBrush(Color::Black));
// pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-nSidePos+1,ptBigScale[1].Y+1),&SolidBrush(Color::Black));
// pGraph->DrawString(lpszTitle,-1,&fontSmall,ptBigScale[1],&SolidBrush(Color::White));
// pGraph->DrawString(ptEndTick.x - nSidePos + 1, ptEndTick.y + 1, strFigure);
// pGraph->SetTextColor(RGB(0, 0, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos, ptEndTick.y, strFigure);
}
else if (dMaxAngle * (nTicks - i) - 30 <= 90)
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-25,ptBigScale[2].Y-3),&SolidBrush(fontColor));
// pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-nSidePos+1,ptBigScale[1].Y+1),&SolidBrush(Color::DarkGray));
// pGraph->SetTextColor(RGB(255, 255, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 2 + 1, ptEndTick.y + 3 + 1, strFigure);
// pGraph->SetTextColor(RGB(0, 0, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 2, ptEndTick.y + 3, strFigure);
}
else if (dMaxAngle * (nTicks - i) - 30 < 140)
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[0].X-5,ptBigScale[1].Y),&SolidBrush(fontColor));
// pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-nSidePos+1,ptBigScale[1].Y+1),&SolidBrush(Color::Black));
// pGraph->SetTextColor(RGB(255, 255, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 3 + 1, ptEndTick.y + 1, strFigure);
// pGraph->SetTextColor(RGB(0, 0, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 3, ptEndTick.y, strFigure);
}
else if (dMaxAngle * (nTicks - i) - 30 < 160)
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X,ptBigScale[1].Y-3),&SolidBrush(fontColor));
// pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-nSidePos+1,ptBigScale[1].Y+1),&SolidBrush(Color::Black));
// pGraph->SetTextColor(RGB(255, 255, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 3 + 1, ptEndTick.y + 1, strFigure);
// pGraph->SetTextColor(RGB(0, 0, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 3, ptEndTick.y, strFigure);
}
else
{
pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-1,ptBigScale[2].Y-5),&SolidBrush(fontColor));
// pGraph->DrawString(wcharFigure,-1,&fontSmall,PointF(ptBigScale[1].X-nSidePos+1,ptBigScale[1].Y+5),&SolidBrush(Color::Black));
// pGraph->SetTextColor(RGB(255, 255, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 10 + 1, ptEndTick.y + 1, strFigure);
// pGraph->SetTextColor(RGB(0, 0, 255));
// pGraph->TextOut(ptEndTick.x - nSidePos / 10, ptEndTick.y, strFigure);
}
}
dWidth = fabs(nRadius / 20);
Pen myPen(Color(126, 0, 0, 255), 2);
for (i=0; i<nTicks; i++)
{
for (int j=1; j<nSubTicks; j++) //子刻度
{
Point ptSubStartTick, ptSubEndTick;
double dDrawAngle = ((i * dMaxAngle + 30) + (j * dMinAngle)) * PI / 180;
ptSubStartTick.X = int(center_x - dRadius * sin(dDrawAngle));
ptSubStartTick.Y = int(center_y + dRadius * cos(dDrawAngle));
ptSubEndTick.X = int(center_x - dRadius * sin(dDrawAngle) + dWidth * sin(dDrawAngle));
ptSubEndTick.Y = int(center_y + dRadius * cos(dDrawAngle) - dWidth * cos(dDrawAngle));
pGraph->DrawLine(&myPen,ptSubStartTick,ptSubEndTick);
}
}
int nradius=86;
int rang=16;
int startspeed=40;
int endspeed=80;
int nmode=0;
Rect rt(center_x-nradius,center_y-nradius,nradius*2,nradius*2);
DrawRangArc(pGraph, center_x,center_y,rt, nradius,rang,startspeed,endspeed,nmode);
nradius=86;
rang=16;
startspeed=100;
endspeed=140;
nmode=1;
Rect rt1(center_x-nradius,center_y-nradius,nradius*2,nradius*2);
DrawRangArc(pGraph, center_x,center_y,rt1, nradius,rang,startspeed,endspeed,nmode);
nradius=70;
rang=16;
startspeed=60;
endspeed=130;
nmode=2;
Rect rt2(center_x-nradius,center_y-nradius,nradius*2,nradius*2);
DrawRangArc(pGraph, center_x,center_y,rt2, nradius,rang,startspeed,endspeed,nmode);
}
BOOL CDashBoard::CharToWChar(LPCSTR strChar, unsigned short **sWchar)
{
int nLen = strlen(strChar) + 1;
int nwLen = MultiByteToWideChar(CP_ACP, 0, strChar, nLen, NULL, 0);
MultiByteToWideChar(CP_ACP, 0, strChar, nLen, *sWchar, nwLen);
return TRUE;
}
//#define FACTOR 1
#define FACTOR 1
/*
Point _aNeedleSrc[5][5] = {
{
Point(FACTOR * 0, FACTOR * -5),
Point(FACTOR * -5, FACTOR * 25),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 5, FACTOR * 25)
},{
Point(FACTOR * -4, FACTOR * 0),
Point(FACTOR * -3, FACTOR * 60),
Point(FACTOR * 0, FACTOR * 1000),
Point(FACTOR * 3, FACTOR * 60),
Point(FACTOR * 4, FACTOR * 0)
},{
Point(FACTOR * -3, FACTOR * -13),
Point(FACTOR * -3, FACTOR * 60),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 3, FACTOR * 60),
Point(FACTOR * 3, FACTOR * -13)
},{
Point(FACTOR * -5, FACTOR * -13),
Point(FACTOR * -4, FACTOR * 20),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 4, FACTOR * 20),
Point(FACTOR * 5, FACTOR * -13)
},{
Point(FACTOR * -5, FACTOR * -13),
Point(FACTOR * -4, FACTOR * 65),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 4, FACTOR * 65),
Point(FACTOR * 5, FACTOR * -13)
}
};
*/
/*
static void _DrawLine(const SCALE* pObj, int r1, int r2, float Angel) {
float co = cos(Angel / 180.) * FACTOR;
float si = sin(Angel / 180.) * FACTOR;
int x0 = pObj->x0 * FACTOR - r1 * co;
int y0 = pObj->y0 * FACTOR - r1 * si;
int x1 = pObj->x0 * FACTOR - r2 * co;
int y1 = pObj->y0 * FACTOR - r2 * si;
GUI_AA_DrawLine(x0, y0, x1, y1);
}
*/
void CDashBoard::DrawPitch(Graphics *pGraph,CRect rect,int OxyX,int OxyY)
{
//Pen pen(ARGB(0xFFFF4500),1);
Pen pen(Color(255, 255, 255, 255));
double Angle_PerKm=(double)(300.00f / (m_dMaxValue - m_dMinValue));
double Angel = (Angle_PerKm*m_speedvalue+30);//* PI / 180;
double dDrawAngle = (Angel ) * PI / 180; //
Matrix matrixH(1,0,0,1,OxyX,OxyY); // 定义一个单位矩阵,坐标原点在表盘中央
matrixH.Rotate(Angel); // 时针旋转的角度度
// matrixH.Translate(-OxyX,-OxyY);
Point pointsH[]={
Point(FACTOR * 0, FACTOR * -15),
Point(FACTOR * -15, FACTOR * 30),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 15, FACTOR * 30)
};
Point pointsH1[]={
Point(FACTOR * 0, FACTOR * -5),
Point(FACTOR * -5, FACTOR * 25),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 5, FACTOR * 25)
};
Point pointsH2[]={
Point(FACTOR * -3, FACTOR * -13),
Point(FACTOR * -3, FACTOR * 60),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 3, FACTOR * 60),
Point(FACTOR * 3, FACTOR * -13)
};
Point pointsH3[]={
Point(FACTOR * -5, FACTOR * -13),
Point(FACTOR * -4, FACTOR * 20),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 4, FACTOR * 20),
Point(FACTOR * 5, FACTOR * -13)
};
Point pointsH4[]={
Point(FACTOR * -5, FACTOR * -13),
Point(FACTOR * -4, FACTOR * 65),
Point(FACTOR * 0, FACTOR * 100),
Point(FACTOR * 4, FACTOR * 65),
Point(FACTOR * 5, FACTOR * -13)
};
//Point *pPoint=_aNeedleSrc[0];
matrixH.TransformPoints( pointsH, 4); // 用该矩阵转换points
SolidBrush brush( Gdiplus::Color( 126, 255,0,0 ) ); //半透明红色
pGraph->SetSmoothingMode(SmoothingModeAntiAlias);//平滑处理 抗锯齿
// 取得第一种颜色的R,G,B值
COLORREF Color2=RGB(0,45,145);
COLORREF Color1=RGB(255,255,255);
int r1 = GetRValue(Color1);
int g1 = GetGValue(Color1);
int b1 = GetBValue(Color1);
// 取得第二种颜色的R,G,B值
int r2 = GetRValue(Color2);
int g2 = GetGValue(Color2);
int b2 = GetBValue(Color2);
// CRect rect;
// GetClientRect(&rect);
int iRotation=180;
// 刷子
Gdiplus::LinearGradientBrush linGrBrush(Gdiplus::Rect(0, 0, rect.right,rect.bottom), // 绘制区域
Gdiplus::Color(255, r1, g1, b1), // 第一种颜色
Gdiplus::Color(255, r2, g2, b2), // 第二种颜色
(Gdiplus::REAL)(90 - iRotation)); // 渐变色的角度
//SolidBrush brush1( Gdiplus::Color(126,0,0,255) ); //半透明红色
pGraph->FillPolygon(&brush, pointsH, 4,FillModeAlternate);
//pGraph->FillPolygon(&brush, pointsH, 4,FillModeAlternate);
pGraph->DrawPolygon(&pen, pointsH, 4);
int nRadius = 0;
if (rect.Width() <= rect.Height())
{
nRadius = rect.Width();
}
else
{
nRadius = rect.Height();
}
double dRadius = fabs(nRadius / 2 - nRadius / 16);
int endx = int(OxyX - dRadius * sin(dDrawAngle));
int endy = int(OxyY + dRadius * cos(dDrawAngle));
pGraph->DrawLine(&pen,OxyX,OxyY,endx,endy);
// 得到绘制区域
pGraph->FillEllipse(&linGrBrush,OxyX-10,OxyY-10,20,20);
// pGraph->FillCircle(&brush1,OxyX,OxyY,5);
// fla=(260-0)*m_speedvalue;//(范围最大值-范围最小值)*数据百分比+范围最小值
//CacheGraphics.DrawLine(&pen, midx, midy, midx + (int) (100 * cos(fla * radian)),
//midy + (INT) (100 * sin(fla * radian)));
// CacheGraphics.FillEllipse(&brush,midx-20,midy-20,20,20);
/*
Matrix matrixH(1,0,0,1,OxyX,OxyY); // 定义一个单位矩阵,坐标原点在表盘中央
matrixH.Rotate(SystemTime.wHour*30+SystemTime.wMinute/2.0-180); // 时针旋转的角度度
Point pointsH[] = { Point(0, 0),Point(m_HourWidth, 0),Point(0, m_HourHeight)};
matrixH.Translate(-m_HourWidth/2,-m_HourHeight/6);
matrixH.TransformPoints( pointsH, 3); // 用该矩阵转换points
graph.DrawImage (m_pImageHHour,pointsH, 3);
*/
}
void CDashBoard::DrawRangArc(Graphics *pGraph, int OxyX,int OxyY,Rect rect,int nRadius,int nRang, float startspeed, float endspeed, int nRangMode)
{
//120---0 140--60 300
int arc_startx=startspeed*(300/(m_dMaxValue - m_dMinValue))+120;
if(arc_startx>360) arc_startx-=360;
int arc_starty=(endspeed-startspeed)*(300/(m_dMaxValue - m_dMinValue));
if(arc_starty>360) arc_starty-=360;
double Angle_PerKm=(double)(300.00f / (m_dMaxValue - m_dMinValue));
double Angel = (Angle_PerKm*startspeed+30);//* PI / 180;
double dDrawAngle = (Angel ) * PI / 180; //
int startx = int(OxyX - (nRadius+nRang/2) * sin(dDrawAngle));
int starty = int(OxyY + (nRadius+nRang/2) * cos(dDrawAngle));
int endx = int(OxyX - (nRadius+nRang/2) * sin(dDrawAngle) + nRang * sin(dDrawAngle));
int endy = int(OxyY + (nRadius+nRang/2) * cos(dDrawAngle) - nRang * cos(dDrawAngle));
double Angel1 = (Angle_PerKm*endspeed+30);
double dDrawAngle1 = (Angel1-0.4) * PI / 180; //
int startx1 = int(OxyX - (nRadius+nRang/2) * sin(dDrawAngle1));
int starty1 = int(OxyY + (nRadius+nRang/2) * cos(dDrawAngle1));
int endx1 = int(OxyX - (nRadius+nRang/2) * sin(dDrawAngle1) + nRang * sin(dDrawAngle1));
int endy1 = int(OxyY + (nRadius+nRang/2) * cos(dDrawAngle1) - nRang * cos(dDrawAngle1));
switch(nRangMode)
{
case 0:
{
int nradius=nRadius;
Pen pen1(Color(255, 0, 255, 0), 1);
pGraph->DrawArc(&pen1,Rect(rect.X+nRang/2,rect.Y+nRang/2,nRadius*2-nRang,nRadius*2-nRang),arc_startx+0.5,arc_starty-0.4);
pGraph->DrawArc(&pen1,Rect(rect.X-nRang/2,rect.Y-nRang/2,nRadius*2+nRang,nRadius*2+nRang),arc_startx+0.5,arc_starty-0.4);
pGraph->DrawLine(&pen1,startx,starty,endx,endy);
pGraph->DrawLine(&pen1,startx1,starty1,endx1,endy1);
Pen pen(Color(100, 0, 255, 0), nRang);
pGraph->DrawArc(&pen,rect,arc_startx,arc_starty);
}
break;
case 1:
{
int nradius=nRadius;
Pen pen1(Color(255, 255, 0, 0), 1);
pGraph->DrawArc(&pen1,Rect(rect.X+nRang/2,rect.Y+nRang/2,nRadius*2-nRang,nRadius*2-nRang),arc_startx+0.5,arc_starty-0.4);
pGraph->DrawArc(&pen1,Rect(rect.X-nRang/2,rect.Y-nRang/2,nRadius*2+nRang,nRadius*2+nRang),arc_startx+0.5,arc_starty-0.4);
pGraph->DrawLine(&pen1,startx,starty,endx,endy);
pGraph->DrawLine(&pen1,startx1,starty1,endx1,endy1);
Pen pen(Color(100, 255, 0, 0), nRang);
pGraph->DrawArc(&pen,rect,arc_startx,arc_starty);
}
break;
case 2:
{
int nradius=nRadius;
Pen pen1(Color(255, 255, 255, 0), 1);
pGraph->DrawArc(&pen1,Rect(rect.X+nRang/2,rect.Y+nRang/2,nRadius*2-nRang,nRadius*2-nRang),arc_startx+0.5,arc_starty-0.4);
pGraph->DrawArc(&pen1,Rect(rect.X-nRang/2,rect.Y-nRang/2,nRadius*2+nRang,nRadius*2+nRang),arc_startx+0.5,arc_starty-0.4);
pGraph->DrawLine(&pen1,startx,starty,endx,endy);
pGraph->DrawLine(&pen1,startx1,starty1,endx1,endy1);
Pen pen(Color(126, 255, 255, 0), nRang);
pGraph->DrawArc(&pen,rect,arc_startx,arc_starty);
}
break;
}
}
工业风的界面随着计算机软件计算的发展逐渐衍生出了现在风靡业界的数字孪生应用,也从二维的变成3维实时仿真的UI,大大的增强了数字化虚拟世界的表达现实世界的能力