嵌入式开发之上位机工业风界面实现

      在做测控类的嵌入式系统开发时,一个精美的上位机控制软件UI是可以为系统增色不少,一般会采用组态软件来开发,我们来看看下面的界面

b7246a38df504c85a213f38c4f2c9936.png

是不是非常直观有工业质感,还可以根据实时数据进行动态的显示和动画效果,那这些炫酷的界面是怎么实现的呢,我们来探讨一下相关技术。

     首先我们看到的漂亮精美的画面是一幅一幅的png图片或者gif动图,如果我们能找到方法将这些图片根据状态或采集数据和状态的需要,实时的展示渲染出来是不是就可以了呢。

     渲染技术其实从图像系统出来就一直在进化,游戏是这方面的优秀应用场景,可以用gdi gdiplus opengl vuklan webgpu等技术实现多平台,甚至跨平台的UI

下面是一组工业风的开关,可以用双缓冲的gdi plus方式结合鼠标的操作事件进行切换显示就可以实现形象的工业控制开关

07594d108aad4d15a31da14bd958503e.pngadca1a297f724d17bd8bc10f08719141.pngd42f96cd375d4b62be2a2f735afa64b5.png8d35f2fc4cf945aba3517c403f7dbd89.png0d138901e16f4ae7be7dabf99ed8aba9.png56ef2962b046489abaac42d342cd6e55.png

下面就是一个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);

}

 速度表盘

 b1a2833eddd448c6864aa55ba72c02cf.png68250cf416e04238b75b5d7fed670c01.png0b8c1fdffd7148d7b3c4b30df83213d6.png819d546c3edf41c9931f26599e99bc11.png63e27b0b34654cc99b7d923e57a85a3f.png

 

 同上,速度表盘或者压力表盘也可以照此方式实现,将图片作为背景图,然后自绘表指针,根据实时数据计算算出表针的旋转角度,即可实现一组精美的表盘控件。

// 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,大大的增强了数字化虚拟世界的表达现实世界的能力

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的MFC界面工具,用于与CAN总线通信。本示例使用了Peak的PCAN-USB接口,但是您可以根据需要更改实现以适应您使用的硬件。 首先,您需要包含以下头文件: ```c++ #include "afxwin.h" #include "PCANBasic.h" #include <vector> ``` 接下来,您需要添加以下变量: ```c++ TPCANHandle m_PcanHandle; // CAN接口句柄 TPCANMsg m_TxMsg; // 发送CAN消息 TPCANMsg m_RxMsg; // 接收CAN消息 std::vector<std::string> m_CanBaudrateList; // CAN波特率列表 std::vector<std::string> m_CanMsgTypeList; // CAN消息类型列表 ``` 在对话框类中,您需要添加以下代码: ```c++ class CCanToolDlg : public CDialogEx { // ... public: CCanToolDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CCanToolDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_CAN_TOOL_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() private: BOOL InitPcan(); // 初始化PCAN接口 void DisplayCanBaudrateList(); // 显示CAN波特率列表 void DisplayCanMsgTypeList(); // 显示CAN消息类型列表 void WriteCanMsg(); // 发送CAN消息 void ReadCanMsg(); // 接收CAN消息 CComboBox m_CanBaudrateCombo; // CAN波特率选择框 CComboBox m_CanMsgTypeCombo; // CAN消息类型选择框 CEdit m_CanIdEdit; // CAN ID编辑框 CEdit m_CanDataEdit; // CAN数据编辑框 CButton m_SendBtn; // 发送按钮 CListBox m_MsgListBox; // 消息列表框 }; ``` 在对话框类的构造函数中,您需要初始化以下变量: ```c++ CCanToolDlg::CCanToolDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_CAN_TOOL_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // 初始化CAN接口 m_PcanHandle = PCAN_USBBUS1; m_TxMsg.ID = 0x123; m_TxMsg.LEN = 8; m_TxMsg.MSGTYPE = MSGTYPE_STANDARD; ZeroMemory(m_TxMsg.DATA, sizeof(m_TxMsg.DATA)); m_RxMsg.ID = 0x0; m_RxMsg.LEN = 0; m_RxMsg.MSGTYPE = MSGTYPE_STANDARD; ZeroMemory(m_RxMsg.DATA, sizeof(m_RxMsg.DATA)); // 初始化CAN波特率列表 m_CanBaudrateList.push_back("1 MBit/sec"); m_CanBaudrateList.push_back("500 KBit/sec"); m_CanBaudrateList.push_back("250 KBit/sec"); m_CanBaudrateList.push_back("125 KBit/sec"); m_CanBaudrateList.push_back("100 KBit/sec"); m_CanBaudrateList.push_back("50 KBit/sec"); m_CanBaudrateList.push_back("20 KBit/sec"); m_CanBaudrateList.push_back("10 KBit/sec"); // 初始化CAN消息类型列表 m_CanMsgTypeList.push_back("Standard"); m_CanMsgTypeList.push_back("RTR"); } ``` 在OnInitDialog函数中,您需要调用初始化CAN接口,显示CAN波特率列表和CAN消息类型列表的函数,并将它们与对应的控件关联起来: ```c++ BOOL CCanToolDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 添加 "关于..." 菜单项。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 if (!InitPcan()) { AfxMessageBox(_T("PCAN initialization failed!")); return FALSE; } DisplayCanBaudrateList(); DisplayCanMsgTypeList(); m_CanBaudrateCombo.SetCurSel(0); m_CanMsgTypeCombo.SetCurSel(0); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } ``` 在InitPcan函数中,您需要初始化PCAN接口并打开它: ```c++ BOOL CCanToolDlg::InitPcan() { TPCANStatus status; // Initialize PCAN interface status = CAN_Initialize(m_PcanHandle, PCAN_BAUD_1M, 0, 0, 0); if (status != PCAN_ERROR_OK) return FALSE; // Start the PCAN interface status = CAN_Start(m_PcanHandle); if (status != PCAN_ERROR_OK) { CAN_Uninitialize(m_PcanHandle); return FALSE; } return TRUE; } ``` 在DisplayCanBaudrateList函数中,您需要将CAN波特率列表显示在对应的控件中: ```c++ void CCanToolDlg::DisplayCanBaudrateList() { for (std::vector<std::string>::iterator it = m_CanBaudrateList.begin(); it != m_CanBaudrateList.end(); it++) { CString str(it->c_str()); m_CanBaudrateCombo.AddString(str); } } ``` 在DisplayCanMsgTypeList函数中,您需要将CAN消息类型列表显示在对应的控件中: ```c++ void CCanToolDlg::DisplayCanMsgTypeList() { for (std::vector<std::string>::iterator it = m_CanMsgTypeList.begin(); it != m_CanMsgTypeList.end(); it++) { CString str(it->c_str()); m_CanMsgTypeCombo.AddString(str); } } ``` 在WriteCanMsg函数中,您需要从控件中获取CAN消息数据并发送它: ```c++ void CCanToolDlg::WriteCanMsg() { CString strId, strData; int nId = 0; // Get CAN ID m_CanIdEdit.GetWindowTextW(strId); if (strId.IsEmpty()) { AfxMessageBox(_T("Please input CAN ID!")); return; } nId = _tcstoul(strId, NULL, 16); if (nId > 0x7FF) { AfxMessageBox(_T("CAN ID should be less than or equal to 0x7FF!")); return; } m_TxMsg.ID = nId; // Get CAN data m_CanDataEdit.GetWindowTextW(strData); if (strData.IsEmpty()) { AfxMessageBox(_T("Please input CAN data!")); return; } CString strDataByte; for (int i = 0; i < 8; i++) { strDataByte = strData.Mid(i * 2, 2); if (strDataByte.IsEmpty()) { ZeroMemory(m_TxMsg.DATA + i, 1); } else { m_TxMsg.DATA[i] = _tcstoul(strDataByte, NULL, 16); } } // Get CAN message type int nMsgType = m_CanMsgTypeCombo.GetCurSel(); if (nMsgType == -1) { AfxMessageBox(_T("Please select CAN message type!")); return; } m_TxMsg.MSGTYPE = (nMsgType == 0 ? MSGTYPE_STANDARD : MSGTYPE_RTR); // Send CAN message TPCANStatus status = CAN_Write(m_PcanHandle, &m_TxMsg); if (status != PCAN_ERROR_OK) { AfxMessageBox(_T("CAN message sending failed!")); return; } // Display CAN message in message list box CString strMsg; strMsg.Format(_T("Tx: %03X %02X %02X %02X %02X %02X %02X %02X %02X"), m_TxMsg.ID, m_TxMsg.DATA[0], m_TxMsg.DATA[1], m_TxMsg.DATA[2], m_TxMsg.DATA[3], m_TxMsg.DATA[4], m_TxMsg.DATA[5], m_TxMsg.DATA[6], m_TxMsg.DATA[7]); m_MsgListBox.AddString(strMsg); } ``` 在ReadCanMsg函数中,您需要接收CAN消息并在消息列表框中显示它: ```c++ void CCanToolDlg::ReadCanMsg() { TPCANStatus status; while (TRUE) { // Receive CAN message status = CAN_Read(m_PcanHandle, &m_RxMsg, NULL); if (status != PCAN_ERROR_OK && status != PCAN_ERROR_QRCVEMPTY) break; if (status == PCAN_ERROR_QRCVEMPTY) break; // Display CAN message in message list box CString strMsg; strMsg.Format(_T("Rx: %03X %02X %02X %02X %02X %02X %02X %02X %02X"), m_RxMsg.ID, m_RxMsg.DATA[0], m_RxMsg.DATA[1], m_RxMsg.DATA[2], m_RxMsg.DATA[3], m_RxMsg.DATA[4], m_RxMsg.DATA[5], m_RxMsg.DATA[6], m_RxMsg.DATA[7]); m_MsgListBox.AddString(strMsg); } } ``` 最后,在对话框类中添加以下消息处理函数: ```c++ void CCanToolDlg::OnBnClickedSendBtn() { WriteCanMsg(); } afx_msg void CCanToolDlg::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { ReadCanMsg(); } CDialogEx::OnTimer(nIDEvent); } void CCanToolDlg::OnDestroy() { CDialogEx::OnDestroy(); // Stop the PCAN interface CAN_Stop(m_PcanHandle); // Uninitialize the PCAN interface CAN_Uninitialize(m_PcanHandle); } void CCanToolDlg::OnCbnSelchangeCanBaudrateCombo() { int nBaudrate = m_CanBaudrateCombo.GetCurSel(); if (nBaudrate == -1) return; switch (nBaudrate) { case 0: CAN_Initialize(m_PcanHandle, PCAN_BAUD_1M, 0, 0, 0); break; case 1: CAN_Initialize(m_PcanHandle, PCAN_BAUD_500K, 0, 0, 0); break; case 2: CAN_Initialize(m_PcanHandle, PCAN_BAUD_250K, 0, 0, 0); break; case 3: CAN_Initialize(m_PcanHandle, PCAN_BAUD_125K, 0, 0, 0); break; case 4: CAN_Initialize(m_PcanHandle, PCAN_BAUD_100K, 0, 0, 0); break; case 5: CAN_Initialize(m_PcanHandle, PCAN_BAUD_50K, 0, 0, 0); break; case 6: CAN_Initialize(m_PcanHandle, PCAN_BAUD_20K, 0, 0, 0); break; case 7: CAN_Initialize(m_PcanHandle, PCAN_BAUD_10K, 0, 0, 0); break; } } void CCanToolDlg::OnBnClickedReadBtn() { SetTimer(1, 100, NULL); } ``` 这是一个简单的MFC界面工具,用于与CAN总线通信。您可以根据需要进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值