📄 chart.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 + -