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

📄 chart.cpp

📁 一个wince下的画曲线类
💻 CPP
字号:
// Chart.cpp : implementation file
//

#include "stdafx.h"
#include "Chart.h"
#include <math.h>

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

#define ZoomOut   4
#define ZoomIn    5
#define BTN_Down   1
#define Zoom_True  2

/////////////////////////////////////////////////////////////////////////////
// CChart

CChart::CChart()
{
	//初始化控件属性
 	m_strXCaption = _T("X轴");
 	m_strYCaption = _T("Y轴");
	m_iTemp = 0;
	m_iZoomFlag = 0;
	m_iZoomAdd = 0;
	m_iZoomCount = 0;
	m_iTempLength = 0;
	m_iXDiv = 0;
	m_iYDiv = 0;
	m_ilength = 0;
//	m_iZoomFlag1 = 0;
	m_iZoomFlag2 = 0;
//	m_iZoomCount1 = 0;
}

CChart::~CChart()
{
}


BEGIN_MESSAGE_MAP(CChart, CWnd)
	//{{AFX_MSG_MAP(CChart)
	ON_WM_TIMER()
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//************************************
// Method:    InvalidateCtrl
// FullName:  CChart::InvalidateCtrl
// Access:    public 
// Returns:   void
// Qualifier: 用于刷新控件显示
//************************************
void CChart::InvalidateCtrl()
{
	CPen SolidPen;   //边框颜色
	SolidPen.CreatePen(PS_SOLID,1,m_crGridColor);
	
	CFont xFont,yFont; //x,y轴坐标
  
	CBrush Brush;      //背景颜色
	Brush.CreateSolidBrush(m_crBackColor);
	
	CRect rectClient;        //客户区大小
	GetClientRect(rectClient);

	//画图区大小
	rectLine.left = rectClient.left + 30;
	rectLine.right = rectClient.right - 10;
	rectLine.top = rectClient.top + 10 ;
	rectLine.bottom = rectClient.bottom - 20;
	
	CClientDC dc(this);
	
	//创建表格设备环境以及创建相应缓冲区
	if (m_dcGrid.GetSafeHdc() == NULL)
	{
		m_dcGrid.CreateCompatibleDC(&dc);
		m_bitmapGrid.CreateCompatibleBitmap(&dc,rectClient.Width(),rectClient.Height());
		m_dcGrid.SelectObject(&m_bitmapGrid);
	}
	
	//设置背景颜色
	m_dcGrid.FillRect(rectClient,&Brush);
	

	//画边框
	m_dcGrid.SelectObject(&SolidPen);
	m_dcGrid.MoveTo(rectClient.left + 30,rectClient.top + 10);
	m_dcGrid.LineTo(rectClient.right - 10,rectClient.top + 10);
	m_dcGrid.LineTo (rectClient.right - 10,rectClient.bottom - 20) ;
	m_dcGrid.LineTo (rectClient.left + 30 , rectClient.bottom - 20) ;
	m_dcGrid.LineTo (rectClient.left + 30 , rectClient.top  + 10) ;
	
	//创建Y轴字体
	yFont.CreateFont (14, 0, 900, 0, 300,
		FALSE, FALSE, 0, ANSI_CHARSET,
		OUT_DEFAULT_PRECIS, 
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY, 
		DEFAULT_PITCH|FF_SWISS, _T("宋体")) ;
	
	//创建X轴字体
	xFont.CreateFont (14, 0, 0, 0, 300,
		FALSE, FALSE, 0, ANSI_CHARSET,
		OUT_DEFAULT_PRECIS, 
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY, 
		DEFAULT_PITCH|FF_SWISS, _T("宋体")) ;
	
	//画Y坐标标题
	m_dcGrid.SetTextColor(m_crTextColor);
	m_dcGrid.SelectObject(&yFont);
	m_dcGrid.ExtTextOut (rectClient.left + 2, 
		(rectClient.top + rectClient.bottom ) / 2 + 5, ETO_CLIPPED,NULL,m_strYCaption,wcslen(m_strYCaption),NULL) ;
	
	//画Y坐标最大值
	CString strTmp;
	strTmp.Format(_T("%.2f"),m_dYMaxValue);
	m_dcGrid.ExtTextOut (rectClient.left+13  , 
		rectClient.top + 40 , ETO_CLIPPED,NULL
		,strTmp,strTmp.GetLength(),NULL) ;
	
	//画Y坐标最小值
	strTmp.Format(_T("%.2f"),m_dYMinValue);
	m_dcGrid.ExtTextOut (rectClient.left+13 , 
		rectClient.bottom - 18 , ETO_CLIPPED,NULL
		,strTmp,strTmp.GetLength(),NULL) ;
	
	//画X坐标标题
	m_dcGrid.SelectObject(&xFont);
	m_dcGrid.ExtTextOut ((rectClient.left+ rectClient.right)/2 - 5, 
		rectClient.bottom - 18 , ETO_CLIPPED,NULL,m_strXCaption,wcslen(m_strXCaption) ,NULL) ;
	
	//画X坐标最大值
	strTmp.Format(_T("%.2f"),m_dXMaxValue);
	m_dcGrid.ExtTextOut (rectClient.right - 40, 
		rectClient.bottom - 18 , ETO_CLIPPED,NULL
		,strTmp,strTmp.GetLength(),NULL) ;
	
	//画X坐标最小值
	strTmp.Format(_T("%.2f"),m_dXMinValue);
	m_dcGrid.ExtTextOut (rectClient.left + 20, 
		rectClient.bottom - 18 , ETO_CLIPPED,NULL
		,strTmp,strTmp.GetLength(),NULL) ;
	
	//创建画线设备环境以及创建相应缓冲区
	if (m_dcLine.GetSafeHdc() == NULL)
	{
		m_dcLine.CreateCompatibleDC(&dc) ;
		m_bitmapLine.CreateCompatibleBitmap(&dc, rectClient.Width(), rectClient.Height()) ;
		m_dcLine.SelectObject(&m_bitmapLine) ;
	}

	//删除创建的GDI对象
	SolidPen.DeleteObject();
	xFont.DeleteObject();
	yFont.DeleteObject();
	Brush.DeleteObject();	
}

//************************************
// Method:    GpToSp
// FullName:  CChart::GpToSp
// Access:    public 
// Returns:   CPoint*
// Qualifier: 将添加的double数组点值转换成屏幕坐标
// Parameter: double * point  double*数组
// Parameter: long llength    数据长度
// Parameter: double dx       x轴分辨率
// Parameter: double dy       y轴分辨率
//************************************
CPoint* CChart::GpToSp(double* point, long llength, double dx, double dy)
{
	rPoint = new CPoint[llength];
	for (int i =0 ;i < llength;i++)
	{
		rPoint[i].x = rectLine.left + 1 + i * dx;
		rPoint[i].y = rectLine.bottom - 10 - (point[i] - m_dYMinValue) * dy;
	}
	return rPoint;	
}

//************************************
// Method:    AddPoint
// FullName:  CChart::AddPoint
// Access:    public 
// Returns:   void
// Qualifier: 添加一个点
// Parameter: double dPointX  横坐标(暂时没用)
// Parameter: double dPointY  纵坐标
//************************************
void CChart::AddPoint( double dPointX, double dPointY )
{
	CPen penLine;
	double dTemp; //临时数据
	
	//x轴分辨率 = 划线区宽度 - 2 除以 数据长度减1
	m_iXDiv = (rectLine.right - 2 - rectLine.left)/double(m_ilength - 1);	
    
	//初始话坐标轴
	if (m_iTemp == 0)
	{
		m_dYMinValue = dPointY;
		m_dYMaxValue = dPointY;
		m_dXMinValue = 0;
		m_dXMaxValue = m_ilength;
		dTemp = m_dYMaxValue;
		m_dSignalSource = new double[m_ilength];
	}

	dTemp = dPointY;
	m_dSignalSource[m_iTemp] = dTemp;

	//获取曲线的最大值和最小值
	if (m_iTemp >= 1)
	{
		if (dTemp >= m_dYMaxValue)
		{
			m_dYMaxValue = dTemp;
		}
		if (dTemp < m_dYMinValue)
		{
			m_dYMinValue = dTemp;
		}
	}

	m_iTemp ++;
	if (m_iTemp == m_ilength)
	{
		m_iTemp = 0;
		//Y轴分辨率 = 画线区高度减20个像素
		//(为了曲线始终在画线区中间并与顶部和底部保持10个像素)除以峰峰值
		m_iYDiv =  (rectLine.Height() - 20)/(m_dYMaxValue - m_dYMinValue);
		//坐标变换
		m_PPoints = GpToSp(m_dSignalSource, m_ilength, m_iXDiv, m_iYDiv);
		//求得实际坐标顶部底部的最大最小值
		m_dYMinValue = m_dYMinValue - (10.000/m_iYDiv);
		m_dYMaxValue = m_dYMaxValue + (10.000/m_iYDiv);

		InvalidateCtrl();

		penLine.CreatePen(PS_SOLID, 1, m_crLineColor) ;
		m_dcLine.SelectObject(&penLine);

		//画线
		for(int i = 1; i< m_ilength;i++)
		{
			m_dcLine.MoveTo (m_PPoints[i - 1].x, m_PPoints[i -1].y);	
			m_dcLine.LineTo (m_PPoints[i].x,m_PPoints[i].y);
			Invalidate();
		}
		//delete rPoint;
	}

	//删除画笔GDI对象
	penLine.DeleteObject();
}
/////////////////////////////////////////////////////////////////////////////
// CChart message handlers
void CChart::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	CRect rectClient;
	GetClientRect(rectClient) ;
	
	CDC memDC ;
	CBitmap memBitmap ;
	CBitmap* oldBitmap ;
	
	memDC.CreateCompatibleDC(&dc) ;
	memBitmap.CreateCompatibleBitmap(&dc, rectClient.Width(), rectClient.Height()) ;
	oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap);
	
	//将m_dcGrid和m_dcLine绘制到控件上
	if (memDC.GetSafeHdc() != NULL)
	{
		memDC.BitBlt(0, 0, rectClient.Width(), rectClient.Height(), 
			         &m_dcGrid, 0, 0, SRCCOPY) ;
		memDC.BitBlt(0, 0, rectClient.Width(), rectClient.Height(), 
			         &m_dcLine, 0, 0, SRCINVERT) ;
		dc.BitBlt(0, 0, rectClient.Width(), rectClient.Height(), 
			&memDC, 0, 0, SRCCOPY);
	}
	
	memDC.SelectObject(oldBitmap) ;		
	
	//删除内存位图GDI对象
	memBitmap.DeleteObject();
	//删除内存绘图环境
	memDC.DeleteDC();	
	// TODO: Add your message handler code here
	
	// Do not call CWnd::OnPaint() for painting messages
}

BOOL CChart::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	// TODO: Add your specialized code here and/or call the base class
	BOOL result;
	//注册窗体类
	static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW) ;
	//创建窗体类
	result = CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, 
		className, NULL, dwStyle, 
		rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
		pParentWnd->GetSafeHwnd(), (HMENU)nID) ;
	//更新窗体显示
	if (result != 0)
		InvalidateCtrl() ;

	return TRUE;	
}

void CChart::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default

	if (point.x > rectLine.left && point.x < rectLine.right && point.y > rectLine.top && point.y < rectLine.bottom)
	{
//		if (m_iZoomFlag2 == 0)
//		{
			m_iZoomFlag = BTN_Down;
			m_PZOutStart = point;
//		}
	}

	CWnd::OnLButtonDown(nFlags, point);
}

void CChart::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CWnd::OnLButtonUp(nFlags, point);
}

void CChart::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
//	CPoint PTemp;
	if (m_iZoomFlag2 == Zoom_True)
	{
		m_iZoomCount ++;
		if (m_iZoomCount % 2 == 0)
		{
			//PTemp = point;
			if (point.x > m_PZOutEnd.x && point.y < m_PZOutEnd.y)
			{
				m_iZoomAdd ++;
			}
			if (m_iZoomAdd == 3) //鼠标6次移动以相同方向
			{
				m_iZoomFlag = ZoomOut;
				SetTimer(1,50,NULL);
				m_iZoomAdd = 0;
				m_iZoomCount = 0;
				m_iZoomFlag2 = 0;
			}
		}
	}
	else
	{
		//判断左键是否按下
		if(m_iZoomFlag == BTN_Down)
		{
			//判断是否是鼠标抖动 (坐标在起始点+-20像素内抖动)
			if (abs(point.x - m_PZOutStart.x) < 10 && abs(point.y - m_PZOutStart.y) < 10)
			{
//				m_iZoomFlag = 0;
			}
			else
			{
				m_iZoomFlag2 = Zoom_True;
				//			PTemp = point;
				m_PZOutEnd = point;
				m_iZoomAdd = 0;
				m_iZoomCount = 0;
			}
	}
	}

	CWnd::OnMouseMove(nFlags, point);
}

void CChart::OnTimer(UINT nIDEvent)
{
	if (m_iZoomFlag == ZoomOut)
	{ 
		m_iZoomAdd  = m_iZoomAdd + 10;
		ZoomOutRect.left = rectLine.left + m_iZoomAdd;
		ZoomOutRect.top = rectLine.top + m_iZoomAdd;
		ZoomOutRect.right = rectLine.right - m_iZoomAdd;
		ZoomOutRect.bottom = rectLine.bottom - m_iZoomAdd;
		ZOOMOut(ZoomOutRect);
		if (abs(ZoomOutRect.left - m_PZOutStart.x) < 10)
		{
			m_iZoomAdd = 0;
			KillTimer(1);
		}
	}
}

//************************************
// Method:    ZOOMOut
// FullName:  CChart::ZOOMOut
// Access:    public 
// Returns:   void
// Qualifier: 放大
// Parameter: CRect & rect  放大区域
//************************************
void CChart::ZOOMOut(CRect &rect)
{
	//假如不是第一次放大,先清空前次曲线
	if(m_iZoomCount > 0)
	{
		CPen penLine;
		penLine.CreatePen(PS_SOLID, 1, RGB(0,0,0)); //与背景颜色一致
		m_dcLine.SelectObject(&penLine);
		
		if (m_dcLine.GetSafeHdc() != NULL)
		{
			for (int i = 1;i<m_iTempLength;i++)
			{
				m_dcLine.MoveTo (m_PZOutPoints[i - 1].x, m_PZOutPoints[i -1].y) ;	
				m_dcLine.LineTo (m_PZOutPoints[i].x,m_PZOutPoints[i].y) ;
			}	   
		}
		Invalidate();		
		delete m_PZOutPoints;
		delete m_dZOOMOutSignal;
	}

	int iTempX1,iTempX2; //放大区域中所含的数组点的上下边界
	double dTemp;
	double dXDivNew, dYDivNew;  //放大时的XY轴分辨率
	iTempX1 = (rect.left - rectLine.left)/m_iXDiv;
	iTempX2 = (rect.right - rectLine.left)/m_iXDiv;
	m_iTempLength = iTempX2 - iTempX1;
	dXDivNew = (rectLine.right - 2 - rectLine.left)/double(m_iTempLength - 1);
	m_PZOutPoints = new CPoint[m_iTempLength];
	m_dZOOMOutSignal = new double[m_iTempLength];
	for (int i = 0;i<m_iTempLength;i++)
	{
		m_dZOOMOutSignal[i] = m_dSignalSource[i + iTempX1];
	}
	//取得放大后的最大最小值
	m_dYMinValue = m_dZOOMOutSignal[0];
	m_dYMaxValue = m_dZOOMOutSignal[0];
	for (i = 0;i<m_iTempLength;i++)
	{
		if (m_dZOOMOutSignal[i] >= m_dYMaxValue)
		{
			m_dYMaxValue = m_dZOOMOutSignal[i];
		}
		if (m_dZOOMOutSignal[i] < m_dYMinValue)
		{
			m_dYMinValue = m_dZOOMOutSignal[i];
		}
	}
	//每次最大最小值改变后重绘边框区域
	InvalidateCtrl();
	dYDivNew = (rectLine.Height() - 20)/(m_dYMaxValue - m_dYMinValue);
	for (i = 0;i<m_iTempLength;i++)
	{
		dTemp = rectLine.bottom - 10 - (m_dZOOMOutSignal[i] - m_dYMinValue) * dYDivNew;	
		m_PZOutPoints[i] = CPoint(rectLine.left + 1 + i * dXDivNew,dTemp);
	}
	Clear();

	CPen penLine;
	penLine.CreatePen(PS_SOLID, 1, m_crLineColor) ;
	m_dcLine.SelectObject(&penLine);

	if (m_dcLine.GetSafeHdc() != NULL)
	{
		for (i = 1;i<m_iTempLength;i++)
		{
			m_dcLine.MoveTo (m_PZOutPoints[i - 1].x, m_PZOutPoints[i -1].y) ;	
			m_dcLine.LineTo (m_PZOutPoints[i].x,m_PZOutPoints[i].y) ;
		}	   
	}
	m_iZoomCount ++ ;
	penLine.DeleteObject();
	//更新显示
	Invalidate();
}

//************************************
// Method:    Clear
// FullName:  CChart::Clear
// Access:    public 
// Returns:   void
// Qualifier: 清空曲线
//************************************
void CChart::Clear()
{
	if (m_ilength != 0)
	{
		CPen penLine;
		
		//m_PPoints = new CPoint[m_ilength];
		penLine.CreatePen(PS_SOLID, 1, RGB(0,0,0)) ;
		m_dcLine.SelectObject(&penLine);
		for (int i = 1;i<m_ilength + 1;i++)
		{
			m_dcLine.MoveTo(m_PPoints[i - 1].x, m_PPoints[i -1].y) ;	
			m_dcLine.LineTo(m_PPoints[i].x,m_PPoints[i].y) ;
		}
		
		penLine.DeleteObject();
		//更新显示
		Invalidate();
	}

//	delete m_PPoints;
}

//************************************
// Method:    UpdateChart
// FullName:  CChart::UpdateChart
// Access:    public 
// Returns:   void
// Qualifier: 曲线边框大小改变后更新当前显示曲线
//************************************
void CChart::UpdateChart()
{
	Clear();
	CPen penLine;
	
	//m_PPoints = new CPoint[m_ilength];
	penLine.CreatePen(PS_SOLID, 1, m_crLineColor) ;
	m_dcLine.SelectObject(&penLine);
	
	m_iXDiv = (rectLine.right - 2 - rectLine.left)/double(m_ilength - 1);
	m_iYDiv =  (rectLine.Height() - 20)/(m_dYMaxValue - m_dYMinValue);
	m_PPoints = GpToSp(m_dSignalSource, m_ilength, m_iXDiv, m_iYDiv);
	for (int i = 1; i < m_ilength;i++)
	{
		m_dcLine.MoveTo (m_PPoints[i - 1].x, m_PPoints[i -1].y);	
		m_dcLine.LineTo (m_PPoints[i].x,m_PPoints[i].y);
		Invalidate();
	}
	return;		
}

⌨️ 快捷键说明

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