本文参考pudn上一个完整工程,在pudn搜索“50815867CurveDrawing”即可找到源代码。

  

上图是使用VS2010重写了该软件后的效果图,下面再贴出关键代码:

// Plot.cpp : 实现文件
// #include "stdafx.h"
#include "CurveDrawing.h"
#include "Plot.h" // CPlot IMPLEMENT_DYNAMIC(CPlot, CWnd) /***********************************************************************************************
*函数名 : CPlot
*函数功能描述 : CPlot类的构造函数,初始化一些变量
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
CPlot::CPlot()
{
//画图区域与整个显示区域的边界
leftmargin=; //左边界
rightmargin=; //右边界
topmargin=; //上边界
bottommargin=; //下边界 m_crBrgndColor = RGB(,,); //背景色
m_crGridPen = RGB(,,); //格子线
m_crCurve = RGB(,,);
m_pValue = NULL;
m_dLen = ;
m_LastValue = ;
} /***********************************************************************************************
*函数名 : DrawCurve
*函数功能描述 : 画曲线图
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::DrawCurve(CDC *pDC)
{
long i=;
float randValue = (double)abs(rand()%); //randValue 范围 0 - 20
float cy = randValue/; //刻度线分为4格
if(cy <= ) //cy <= 1的概率是25%
{
cy = ;
} if(cy == )
{
AddPoint(CTime::GetCurrentTime(),m_LastValue);
}
else
{
AddPoint(CTime::GetCurrentTime(),cy);
} CPen *oldpen;
CPen pen(PS_SOLID,,m_crCurve);
oldpen = pDC->SelectObject(&pen); float smallgridwidth = (float)m_skeletonRect.Width()/;
float intervalY = m_skeletonRect.Height()/; int docnumber1 = m_dLen;
int offset=; if(m_dLen >=)
{
if(m_dLen < )
{
for(int i=;i<m_dLen-;i++) //画图都是从左向右,左边的点都是先出来的点,但视觉效果是从右向左
{
docnumber1--;
/*pDC->Ellipse(m_skeletonRect.left+smallgridwidth*(100-docnumber1)-offset,m_skeletonRect.Height()+topmargin-((m_pValue[i].dValue-1)*intervalY)-offset,m_skeletonRect.left+smallgridwidth*(100-docnumber1)+offset,
m_skeletonRect.Height()+topmargin-((m_pValue[i].dValue-1)*intervalY)+offset);
pDC->Ellipse(m_skeletonRect.left+smallgridwidth*(100-docnumber1+1)-offset,m_skeletonRect.Height()+topmargin-((m_pValue[i+1].dValue-1)*intervalY)-offset,m_skeletonRect.left+smallgridwidth*(100-docnumber1+1)+offset,
m_skeletonRect.Height()+topmargin-((m_pValue[i+1].dValue-1)*intervalY)+offset);*/ pDC->MoveTo(CPoint(m_skeletonRect.right-(float)smallgridwidth*(docnumber1),m_skeletonRect.Height()+topmargin-
((m_pValue[i].dValue-)*intervalY)));
pDC->LineTo(CPoint(m_skeletonRect.right-(float)smallgridwidth*(docnumber1-),m_skeletonRect.Height()+topmargin-
((m_pValue[i+].dValue-)*intervalY)));
}
}
else
{
for(i=;i<;i++)
{
for(int i=;i<;i++) //同理 这里也是从左向右描点
{
/*pDC->Ellipse(m_skeletonRect.left+smallgridwidth*(i)-offset,m_skeletonRect.Height()+topmargin-
((m_pValue[i+m_dLen-1-100].dValue-1)*intervalY)-offset,m_skeletonRect.left+smallgridwidth*(i)+offset,m_skeletonRect.Height()+topmargin-
((m_pValue[i+m_dLen-1-100].dValue-1)*intervalY)+offset); pDC->Ellipse(m_skeletonRect.left+smallgridwidth*(i+1)-offset,m_skeletonRect.Height()+topmargin-
((m_pValue[i+m_dLen-100].dValue-1)*intervalY)-offset,m_skeletonRect.left+smallgridwidth*(i+1)+offset,m_skeletonRect.Height()+topmargin-
((m_pValue[i+m_dLen-100].dValue-1)*intervalY)+offset);*/ pDC->MoveTo(CPoint(m_skeletonRect.right - smallgridwidth*(-i),m_skeletonRect.Height()+topmargin-
((m_pValue[i+m_dLen--].dValue-)*intervalY)));
pDC->LineTo(CPoint(m_skeletonRect.right - smallgridwidth*(-i-),m_skeletonRect.Height()+topmargin-
((m_pValue[i+m_dLen-].dValue-)*intervalY)));
}
}
}
} pDC->SelectObject(oldpen);
} /***********************************************************************************************
*函数名 : DrawTimeValue
*函数功能描述 : 画时间刻度 在刷新背景的的时候画刻度线 避免闪烁
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::DrawTimeValue(CDC *pDC)
{
int i=; if((m_dLen<) & (m_dLen >))
{
int scale = m_dLen/; for(i=;i<=scale;i++)
{
ShowtimeValue(i,pDC);
}
}
else
{
for(i=;i<=;i++)
{
ShowtimeValue(i,pDC);
}
}
} /***********************************************************************************************
*函数名 : ShowtimeValue
*函数功能描述 : 显示某一个时间值
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::ShowtimeValue(int scale,CDC *pDC)
{
CString tmp("");
int x=,y=;
float smallgridwidth = (float)m_skeletonRect.Width()/; tmp = m_pValue[m_dLen--*scale].time.Format("%H:%M:%S");
x = m_skeletonRect.right - smallgridwidth*scale*;
y = m_skeletonRect.bottom; pDC->DrawText(tmp,CRect(x-,y+,x+,y+),DT_CENTER);
} /***********************************************************************************************
*函数名 : AddPoint
*函数功能描述 : 添加点
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::AddPoint(CTime t,float d)
{
if(m_dLen == )
{
m_pValue = (pValue *)malloc(sizeof(pValue));
}
else
{
m_pValue = (pValue *)realloc(m_pValue,(m_dLen+)*sizeof(pValue));
} m_LastValue = d; //记录最近的一个值
m_pValue[m_dLen].time = t;
m_pValue[m_dLen].dValue = d; m_dLen++; //数据量在增加
} /***********************************************************************************************
*函数名 : CPlot
*函数功能描述 : CPlot的析构函数
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
CPlot::~CPlot()
{
if(m_pValue != NULL)
{
free(m_pValue);
m_pValue = NULL;
}
} BEGIN_MESSAGE_MAP(CPlot, CWnd)
END_MESSAGE_MAP() /***********************************************************************************************
*函数名 : DrawBasic
*函数功能描述 : 画背景画方框
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::DrawBasic(CDC *pDC)
{
m_skeletonRect.left = m_Rect.left + leftmargin;
m_skeletonRect.top = m_Rect.top + topmargin;
m_skeletonRect.bottom = m_Rect.bottom - bottommargin;
m_skeletonRect.right = m_Rect.right - rightmargin; CBrush m_bkBrush(m_crBrgndColor);
pDC->SelectObject(&m_bkBrush); pDC->FillRect(m_Rect,&m_bkBrush); pDC->Rectangle(m_skeletonRect);
} /***********************************************************************************************
*函数名 : DrawGrids
*函数功能描述 : 画格子
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::DrawGrids(CDC *pDC)
{
DrawXGrids(pDC);
DrawYGrids(pDC);
} /***********************************************************************************************
*函数名 : DrawXGrids
*函数功能描述 : 画横向的格子
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::DrawXGrids(CDC *pDC)
{
CPen *old,*old1;
CPen pen1(PS_SOLID,,RGB(,,));
CPen pen2(PS_SOLID,,RGB(,,));
CPen pen3(PS_SOLID,,RGB(,,));
CFont *oldFont;
CFont ft; old = (CPen *)pDC->SelectObject(&pen1);
ft.CreatePointFont(,_T("Arial"),pDC);
oldFont = (CFont *)pDC->SelectObject(&ft); int yDiv = ;
double yDistance = ((double)m_skeletonRect.bottom - (double)m_skeletonRect.top)/yDiv;
int startX = m_skeletonRect.left; //左边横坐标
int startY = m_skeletonRect.top; //左边上坐标
int endY = m_skeletonRect.bottom;
int endX = m_skeletonRect.right;
int offset = ;
int scale = ; CString text;
text.Format(_T("%d.0"),);
pDC->DrawText(text,CRect(startX-,startY-,startX-,startY+),DT_CENTER);
pDC->DrawText(text,CRect(endX+,startY-,endX+,startY+),DT_CENTER);
text.Format(_T("%d.0"),);
pDC->DrawText(text,CRect(startX-,endY-,startX-,endY+),DT_CENTER);
pDC->DrawText(text,CRect(endX+,endY-,endX+,endY+),DT_CENTER); int i=;
for(i=;i<=;i++) //画39条格子
{
if(i% == ) //每10格画一个大格子
{
old1 = (CPen *)pDC->SelectObject(&pen2);
pDC->MoveTo(startX+,(int)(startY+i*yDistance));
pDC->LineTo(endX-,(int)(startY+i*yDistance));
pDC->SelectObject(old1); scale--;
text.Format(_T("%d.0"),scale);
pDC->DrawText(text,CRect(startX-,startY+i*yDistance-,startX-,startY+i*yDistance+),DT_CENTER);
pDC->DrawText(text,CRect(endX+,startY+i*yDistance-,endX+,startY+i*yDistance+),DT_CENTER);
} pDC->MoveTo(startX+,(int)(startY+i*yDistance));
pDC->LineTo(endX-,(int)(startY+i*yDistance)); old1 = (CPen *)pDC->SelectObject(&pen3); //画刻度
pDC->MoveTo(startX,(int)(startY+i*yDistance));
pDC->LineTo(startX-offset,(int)(startY+i*yDistance));
pDC->MoveTo(endX,(int)(startY+i*yDistance));
pDC->LineTo(endX+offset,(int)(startY+i*yDistance));
pDC->SelectObject(old1);
} pDC->SelectObject(old);
pDC->SelectObject(oldFont);
} /***********************************************************************************************
*函数名 : DrawYGrids
*函数功能描述 : 画竖向的格子
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CPlot::DrawYGrids(CDC *pDC)
{
CPen *old,*old1;
CPen pen1(PS_SOLID,,RGB(,,)); //细线
CPen pen2(PS_SOLID,,RGB(,,));
CPen pen3(PS_SOLID,,RGB(,,)); //画刻度 old = (CPen *)pDC->SelectObject(&pen1); //横向分为100个点
int xDiv = ;
double xDistance = ((double)m_skeletonRect.right - (double)m_skeletonRect.left)/xDiv;
int startX = m_skeletonRect.left; //左边横坐标
int startY = m_skeletonRect.top; //左边上坐标
int endY = m_skeletonRect.bottom;
int endX = m_skeletonRect.right;
int offset = ; int i=;
for(i=;i<=;i++) //画99条格子
{
if(i% == ) //每10格画一个大格子
{
old1 = (CPen *)pDC->SelectObject(&pen2); pDC->MoveTo(startX+i*xDistance,startY+);
pDC->LineTo(startX+i*xDistance,endY-); pDC->SelectObject(old1);
}
pDC->MoveTo(startX+i*xDistance,startY+);
pDC->LineTo(startX+i*xDistance,endY-); old1 = (CPen *)pDC->SelectObject(&pen3); //画刻度
pDC->MoveTo(startX+i*xDistance,startY-offset);
pDC->LineTo(startX+i*xDistance,startY);
pDC->MoveTo(startX+i*xDistance,endY);
pDC->LineTo(startX+i*xDistance,endY+offset);
pDC->SelectObject(old1);
} pDC->SelectObject(old);
}

上面的代码有注释,也没有什么难的。分为绘制背景图和绘制曲线图,绘制曲线图的时候无论数据点大于100个还是小于100个,每次描点都是从左向右描的,恰好跟视觉效果相反,是不是有种眼睛被欺骗了的感觉。绘制背景是在相应视图的WM_ERASEBKGND消息响应中完成的,而且使用了双缓冲。绘制曲线图是在相应视图的OnDraw函数中完成的。

下面再给出这两个函数:

/***********************************************************************************************
*函数名 : OnDraw
*函数功能描述 : 视类的OnDraw虚函数,在窗口重绘时被WM_PAINT的消息响应函数调用
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
void CMyView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument(); if(m_bRedraw == TRUE) //避免其他情况引起的重绘
{
m_bRedraw = FALSE;
m_plot.DrawCurve(pDC);
}
}
/***********************************************************************************************
*函数名 : OnEraseBkgnd
*函数功能描述 : WM_ERASEBKGND消息响应函数
*函数参数 : 无
*函数返回值 : 无
*作者 : nelson
*函数创作日期 : 2016/3/15
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 : 1.0
*历史版本 : 无
***********************************************************************************************/
BOOL CMyView::OnEraseBkgnd(CDC* pDC)
{
GetClientRect(m_plot.m_Rect); CDC MemDC; //内存兼容DC
CBitmap bmp;
MemDC.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC,m_plot.m_Rect.Width(),m_plot.m_Rect.Height());
MemDC.SelectObject(&bmp); //将兼容位图选入兼容DC m_plot.DrawBasic(&MemDC); //在兼容位图
m_plot.DrawGrids(&MemDC);
m_plot.DrawTimeValue(&MemDC); pDC->BitBlt(m_plot.m_Rect.left,m_plot.m_Rect.top,m_plot.m_Rect.Width(),m_plot.m_Rect.Height(),&MemDC,,,SRCCOPY); MemDC.DeleteDC();
bmp.DeleteObject(); return TRUE;
}

关于多视图,查看CSplitterWnd类即可。

VC实现趋势图绘制的更多相关文章

  1. 【开源】专业K线绘制[K线主副图、趋势图、成交量、滚动、放大缩小、MACD、KDJ等)

    这是一个iOS项目雅黑深邃的K线的绘制. 实现功能包括K线主副图.趋势图.成交量.滚动.放大缩小.MACD.KDJ,长按显示辅助线等功能 预览图 最后的最后,这是项目的开源地址:https://git ...

  2. Excel应该这么玩——7、我是预言家:绘制趋势图

    让我们先看一个场景:你是公司销售部的员工,你手里有公司最近几年的销售额相关的数据,经理希望你预测下个月的销售额.盯着一堆数据,你或许会想到画一张XY坐标图,然后将每个月份的销售额标定为一个坐标.但是下 ...

  3. Echart绘制趋势图和柱状图总结

    1.legend名字与series名字一样,即可联动,且不可手动去掉联动效果 2.通过legend图例联动,隐藏绘制图线后,对应( yAxisIndex: 1)坐标y轴如果没有同时设置min和max的 ...

  4. 用python做自己主动化測试--绘制系统性能趋势图和科学计算

    在性能測试中.我们常常须要画出CPU memory 或者IO的趋势图. 预计大学里.大多数人都学习过matlib, 领略了matlib绘图的强大. python提供了强大的绘图模块matplotlib ...

  5. python3 读取txt文件数据,绘制趋势图,matplotlib模块

    python3 读取txt文件数据,绘制趋势图 test1.txt内容如下: 时间/min cpu使用率/% 内存使用率/% 01/12-17:06 0.01 7.61 01/12-17:07 0.0 ...

  6. matplotlib点线 坐标刻度 3D图绘制(六)

    plot语句中支持除X,Y以外的参数,以字符串形式存在,来控制颜色.线型.点型等要素,语法形式为: plt.plot(X, Y, 'format', ...) 1 点和线的样式 颜色 参数color或 ...

  7. Android实现天气预报温度/气温折线趋势图

     Android实现天气预报温度/气温折线趋势图 天气预报的APP应用中,难免会遇到绘制天气温度/气温,等关于数据趋势的折线或者曲线图,这类关于气温/温度的折线图,通常会有两条线.一条是高温线,一 ...

  8. 矢量图绘制工具Svg-edit调整画布的大小

    矢量图绘制工具Svg-edit调整画布的大小 ------------------------------ ------------------------

  9. Matlab 语谱图(时频图)绘制与分析

    Matlab 语谱图(时频图)绘制与分析 语谱图:先将语音信号作傅里叶变换,然后以横轴为时间,纵轴为频率,用颜色表示幅值即可绘制出语谱图.在一幅图中表示信号的频率.幅度随时间的变化,故也称" ...

随机推荐

  1. Ignite集成Spark之IgniteDataFrames

    下面简要地回顾一下在第一篇文章中所谈到的内容. Ignite是一个分布式的内存数据库.缓存和处理平台,为事务型.分析型和流式负载而设计,在保证扩展性的前提下提供了内存级的性能. Spark是一个流式数 ...

  2. [luoguP4035] [JSOI2008]球形空间产生器(高斯消元)

    传送门 设球心的坐标为未知量 用最后一个点来表示球面到球心的距离,那么它和前n个式子相等 移项乱搞 最后高斯消元 #include <cmath> #include <cstdio& ...

  3. C# 实现刻录光盘功能

    最近公司提出一个需求,要把公司系统的图像刻录成光盘(公司系统是医院放射科系统,很多放射科的图像) 查看了很多资料发现有两个比较可靠 1:使用IMAPI2,进行文件的光盘刻录,具体实例可以参照以下链接: ...

  4. poj 3304 判断是否存在一条直线与所有线段相交

    Segments Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8579   Accepted: 2608 Descript ...

  5. Python入门---易错已错易混淆----知识点

    1.not 1 or 0 and 1 or 3 and 4 or 5 and 6 or 7 and 8 and 9 结果会输出啥? 根据优先级:(not 1) or (0 and 1) or (3 a ...

  6. 自定义header参数时的命名要求

    HTTP头是可以包含英文字母([A-Za-z]).数字([0-9]).连接号(-)hyphens, 也可义是下划线(_).在使用nginx的时候应该避免使用包含下划线的HTTP头.主要的原因有以下2点 ...

  7. hdu3491最小割转最大流+拆点

    题意:求最小割,即求最大流即可.此题之关键为拆点(限制在点),每条边都是双向边,注意一下. 未1A原因:在拆点之后添加边的过程中,要注意,出去的是i`,进来的是i,!!所以,写addegde函数时候 ...

  8. 2017 ACM/ICPC Asia Regional Shenyang Online 记录

    这场比赛全程心态爆炸…… 开场脑子秀逗签到题WA了一发.之后0贡献. 前期状态全无 H题想复杂了,写了好久样例过不去. 然后这题还是队友过的…… 后期心态炸裂,A题后缀数组理解不深,无法特判k = 1 ...

  9. LibieOJ 6165 一道水题 (线性筛)

    题目链接 LOJ6165 题目意思其实就是求LCM(1, 2, 3, ..., n) 直接用线性筛求出1到1e8之间的所有质数 然后对于每个质数p,他对答案的贡献为$p^{i}$ 其中$p^{i}$小 ...

  10. 带你学Node系列之express-CRUD

    前言 hello,小伙伴们,我是你们的pubdreamcc,本篇博文出至于我的GitHub仓库node学习教程资料,欢迎小伙伴们点赞和star,你们的点赞是我持续更新的动力. GitHub仓库地址:n ...