MFC 动态曲线 支持缩放 显示图例(CStatic派生类)(续) .
来源:互联网 发布:还珠格格知画扮演者 编辑:程序博客网 时间:2024/05/16 11:45
小小的创新(至少我没有看到有前人做过,哈哈。。)
(一)关于布局
一般的绘制动态曲线的过程就是,先把坐标定下来,什么地方画轴,什么地方写字。当需要变更布局时,就有点麻烦了。当然也可以定义一些手动设置的属性来控制。本文借助
CSS的布局思想,创建了一些CRect的对象,每个对象绑定一个绘图元素。例如,
- CRect m_rectCtrl; // 获取整个控件的区域
- CRect m_rectPlot; // 用于绘制曲线的区域
- CRect m_rectTitle; // 绘制标题的区域
- CRect m_rectLegend; // 绘制图例的区域
CRect m_rectCtrl; // 获取整个控件的区域CRect m_rectPlot; // 用于绘制曲线的区域CRect m_rectTitle; // 绘制标题的区域CRect m_rectLegend; // 绘制图例的区域
坐标轴、曲线、图例等元素都在指定的CRect绘制。同时定义一些属性用来控制几个CRect的相对位置,这样要改变布局只需要修正他们的相对位置即可,呵呵。。
(二)关于缩放
由于真实系统中各点坐标都是浮点数,而MFC中CPoint的坐标是整数。所以一般是向直线中加入一个新的点是,都按一定的公式转化为CPoint的整数坐标值。但这样对缩放操作
不是很方便。本项目中,为每个直线对象(CLine类的对象,CLine是自定义的,它有很多和该线相关的属性,如线型、线宽、颜色等,同时包含一个点的数组,点的坐标都是float
型的)内部的点都以float型存储,在要绘制曲线时,临时申请一个CPoint型的数组,用于绘图。
同时每个坐标轴(Axis类,也是自定义类)都带有指示该坐标轴表示范围的属性。在计算上述CPoint的值时,需要联合CLine和Axis两个属性值确定。当在进行缩放时,只需要改
变坐标轴的范围即可。当在进行下一次绘图时,计算的CPoint坐标值会自动改变。从而实现了缩放。
但这也会带来一个问题,刚才已经说过,绘制曲线实在m_rectPlot矩形框中的。缩放时必然会有点的坐标超出这个矩形。出现如下的情况:
要解决这个问题可不容易,最简单的方法是,如果某一个点的某一维坐标值超出矩形,则就将其限定在矩形的那个边上,但这样图像看起来有点奇怪。
复杂的方法是,遍历所有的点,判断每个点是否在矩形内部,分多种情况:
①如果上一点和该点都在矩形内部,则从上一个点LineTo()当前的点;
②如果上一个点不在矩形内,当前的点在矩形内部,或者当前的点不在矩形内部,而上一个点在矩形内部,则需要计算这两个点的连线与矩形的交点,并绘制
一条从交点到矩形内部那个点的直线;
③如果上一个点和当前的点都不在矩形内部,则什么也不做。
这里还需要自己写几个函数,
- // 求两个矩形 rect1 和 rect2 的交集矩形
- CRect IntersectionRect(const CRect& rect1,const CRect& rect2);
- // 判断一个点是否在矩形上
- BOOL PointOnRect(const CRect& rect,const CPoint& point );
- // 判断一个点point是否在矩形rect内部
- BOOL PointInRect(const CRect& rect,const CPoint& point );
- // 求两个点之间连线与rect边的交点
- CPoint IntersectionRectLine(const CRect& rect,const CPoint& inPoint,const CPoint& exPoint );
// 求两个矩形 rect1 和 rect2 的交集矩形CRect IntersectionRect(const CRect& rect1,const CRect& rect2);// 判断一个点是否在矩形上BOOL PointOnRect(const CRect& rect,const CPoint& point );// 判断一个点point是否在矩形rect内部BOOL PointInRect(const CRect& rect,const CPoint& point );// 求两个点之间连线与rect边的交点CPoint IntersectionRectLine(const CRect& rect,const CPoint& inPoint,const CPoint& exPoint );
这里面就有点算法的内容,当然我用的算法肯定不是最好的,还望广大网友指正,尤其是最后一个函数,情况有点复杂
缩放后如何恢复呢?在这种结构下就非常简单了,用一个数据记录最初始的坐标轴范围,当鼠标双击时,将当前的坐标轴范围更改为最原始的那个范围,按照缩放的原理,自
然复原了。
(三)关于鼠标响应事件
要实现更复杂的功能,离不开响应鼠标事件。当然“CStatic控件响应鼠标” ,Google一下可以得到完美解答,这里就顺便提及一下。也是最简单的方法。
①在“资源视图”中,找到你用于绘制曲线的CStatic控件,将属性“Notify”改为True;
②编写的CStatic继承类的.h文件中添加
- DECLARE_MESSAGE_MAP()
- afx_msg void OnLButtonDown(UINT nFlag,CPoint point);
- afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
- afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()afx_msg void OnLButtonDown(UINT nFlag,CPoint point);afx_msg void OnLButtonUp(UINT nFlags, CPoint point);afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
③在CStatic继承类的实现的.cpp文件中添加消息映射:
- BEGIN_MESSAGE_MAP(CPlot, CStatic)
- ON_WM_LBUTTONDOWN()
- ON_WM_LBUTTONUP()
- ON_WM_LBUTTONDBLCLK()
- END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CPlot, CStatic)ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_LBUTTONDBLCLK()END_MESSAGE_MAP()
并实现上述三个函数。
OK,大功告成,MFC下绘制动态曲线的任务就完成啦,下面贴出.h文件,供大家参考,欢迎讨论。
完整资源请到 上一篇博文给出的地址进行下载。
- #pragma once
- #include <vector>
- using namespace std;
- namespace RealtimeCurve{
- const int MaxPointsCount = 512; // 曲线最大存储点数
- const int MaxLinesCount = 10; // 控件容纳最大曲线个数
- class CLine
- {
- public:
- CLine(CString name=_T(""),
- int lineStyle = PS_SOLID,
- COLORREF lineColor = RGB(255,0,0),
- int lineWidth = 2);
- CLine(const CLine& nLine);
- CLine& operator = (const CLine& nLine);
- ~CLine();
- _declspec(property(get = getLineName,put = setLineName)) CString lineName;
- _declspec(property(get = getShowStatus,put = setShowStatus)) BOOL showStatus;
- _declspec(property(get = getLineColor,put = setLineColor)) COLORREF lineColor;
- _declspec(property(get = getLineType,put = setLineType)) int lineType;
- _declspec(property(get = getLineWidth,put = setLineWidth)) int lineWidth;
- void AddPoint(float x, float y);
- float GetPointX(int nIndex);
- float GetPointY(int nIndex);
- int GetPointCount();
- inline CString getLineName() { return this->LineName; }
- inline void setLineName(CString name) { this->LineName = name; }
- inline BOOL getShowStatus() { return this->IsShow; }
- inline void setShowStatus(BOOL showStatus){ this->IsShow = showStatus; }
- inline COLORREF getLineColor() { return this->LineColor;}
- inline void setLineColor(COLORREF color){ this->LineColor = lineColor; };
- inline int getLineType() { return this->LineType;}
- inline void setLineType(int lineType) { this->LineType = lineType; };
- inline int getLineWidth() { return this->LineWidth;}
- inline void setLineWidth(int lineWidth) { this->LineWidth = lineWidth; };
- public:
- CString LineName; // 曲线名称
- BOOL IsShow; // 曲线是否显示
- COLORREF LineColor; // 颜色
- int LineType; // 线型 solid,dash
- int LineWidth; // 线宽 pixel
- struct Point{
- float x;
- float y;
- };
- private:
- int m_currentSize; // 有效的坐标点数
- Point * m_pointArrayPtr; // 存储曲线中Point的数组
- CRITICAL_SECTION g_cs ;
- };
- class CAxis
- {
- public:
- struct AxisRangeStruct{ // 坐标轴范围
- float AxisMinValue; // 轴最小值
- float AxisMaxValue; // 轴最大值
- };
- CAxis(COLORREF color = RGB(0,255,0),
- int style = PS_SOLID,
- int width = 2,
- float minValue = 0.0f,
- float maxValue = 500.0);
- ~CAxis(){ }
- CAxis(const CAxis& axis);
- CAxis &operator = (const CAxis& axis);
- inline void SetAxisRange(float minValue=0.0f,float maxValue=500.0f){
- m_axisRange.AxisMinValue = minValue;
- m_axisRange.AxisMaxValue = maxValue;
- }
- inline float GetAxisRange(){
- return this->m_axisRange.AxisMaxValue-this->m_axisRange.AxisMinValue;
- }
- inline float GetRangeLowerLimit() { return this->m_axisRange.AxisMinValue; }
- inline float GetRangeUpperLimit() { return this->m_axisRange.AxisMaxValue; }
- public:
- BOOL IsShow; // 是否显示坐标轴
- COLORREF AxisColor; // 颜色
- int AxisStyle; // 线型
- int AxisWidth; // 线宽
- int CoorTextBoxWidth; // 坐标文本框 宽度
- int CoorTextBoxHeight; // 坐标文本框 高度
- private:
- AxisRangeStruct m_axisRange; // 轴代表值的范围
- };
- class CPlot :
- public CStatic
- {
- DECLARE_DYNAMIC(CPlot)
- public:
- CPlot(void);
- virtual ~CPlot(void);
- void Start();
- void Stop();
- void AddNewLine(CString name = _T(""),
- int style = PS_SOLID,
- COLORREF color = RGB(255,0,0),
- int iThick = 2);
- void AddNewPoint(float x,float y,int nLineIndex); //向某一条曲线中添加数据
- CLine* GetLineByIndex(int nIndex); // 得到第nIndex(从0开始)条曲线的引用
- CLine* GetLineByName(CString name); // 根据曲线名称获取曲线
- int GetLineCount(); // 获取当前有效曲线个数
- void SetRate(int nRate);
- void SetBkColor(COLORREF clrBkColor);
- CAxis& GetAxisY();
- CAxis& GetAxisX();
- private:
- void RefreshLayout(); // 刷新页面布局
- void RefreshPlot(CDC* pDC); // 刷新控件
- void DrawBackground(CDC* pDC); // 绘制背景
- void DrawAxises(CDC* pDC); // 绘制坐标轴
- void DrawGrids(CDC* pDC); // 绘制网格
- void DrawLine(CDC* pDC,const CRect& rectZone,const CPoint* pPtr,int nCount);
- void DrawLines(CDC* pDC); // 绘制全部曲线
- void DrawLegend(CDC* pDC,CRect& rectZone); // 绘制图例
- void DrawTile(CDC* pDC,CRect& rectZone); // 绘制标题
- void ScaleProcess(); // 放大操作
- // 求两个矩形 rect1 和 rect2 的交集矩形
- CRect IntersectionRect(const CRect& rect1,const CRect& rect2);
- // 判断一个点是否在矩形上
- BOOL PointOnRect(const CRect& rect,const CPoint& point );
- // 判断一个点point是否在矩形rect内部
- BOOL PointInRect(const CRect& rect,const CPoint& point );
- // 求两个点之间连线与rect边的交点
- CPoint IntersectionRectLine(const CRect& rect,const CPoint& inPoint,const CPoint& exPoint );
- public:
- //float XMoveStep; // 每次移动X轴增加的值
- BOOL ShowGrid; // 是否显示网格
- COLORREF GridColor; // 网格颜色
- int GridStyle; // 网格线型
- int GridWidth; // 网格线宽
- int GridSize; // 网格宽度
- int ShowTextGrap; // 每个多个格显示一个坐标值
- COLORREF BkGndColor; // 背景颜色
- int RefreshRate; // 刷新图像周期,ms
- private:
- BOOL m_bAdjustable; // 是否需要自动调整
- // 布局相关
- CRect m_rectCtrl; // 控件矩形区域
- CRect m_rectPlot; // 绘图矩形区域
- CRect m_rectTitle; // 标题矩形区域
- CRect m_rectLegend; // 图例矩形区域
- int m_marginLeft; // 左侧留白宽度
- int m_marginRight; // 右侧留白宽度
- int m_marginTop; // 上部留白宽度
- int m_marginBottom; // 下部留白宽度
- int m_titleHight; // 标题高度
- int m_legendHeight; // 图例高度
- // 坐标轴相关
- CAxis m_axisX; // X 轴
- CAxis m_axisY; // Y 轴
- float m_vppXAxis; // 每个像素代表的X轴值
- float m_vppYAxis; // 每个像素点代表的Y轴值
- // 曲线相关
- CLine * m_linePtrArray[MaxLinesCount]; // 指针数组
- int validLinesCount; // 有效线的个数
- // 缩放相关
- float m_originXLwLmt,m_originXUpLmt; // 已经在自适应情况下的X,Y轴范围
- float m_originYLwLmt,m_originYUpLmt;
- CPoint m_startPoint,m_endPoint; // 鼠标左键起止点
- public:
- DECLARE_MESSAGE_MAP()
- afx_msg void OnTimer(UINT nIDEvent);
- afx_msg void OnPaint();
- afx_msg BOOL OnEraseBkgnd(CDC* pDC);
- afx_msg void OnSize(UINT nType, int cx, int cy);
- afx_msg void OnLButtonDown(UINT nFlag,CPoint point);
- afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
- afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
- };
- }
#pragma once#include <vector>using namespace std;namespace RealtimeCurve{const int MaxPointsCount = 512;// 曲线最大存储点数const int MaxLinesCount = 10;// 控件容纳最大曲线个数class CLine{public:CLine(CString name=_T(""),int lineStyle = PS_SOLID, COLORREF lineColor = RGB(255,0,0),int lineWidth = 2);CLine(const CLine& nLine);CLine& operator = (const CLine& nLine);~CLine();_declspec(property(get = getLineName,put = setLineName))CString lineName;_declspec(property(get = getShowStatus,put = setShowStatus)) BOOL showStatus;_declspec(property(get = getLineColor,put = setLineColor)) COLORREF lineColor;_declspec(property(get = getLineType,put = setLineType)) int lineType;_declspec(property(get = getLineWidth,put = setLineWidth)) int lineWidth;voidAddPoint(float x, float y);floatGetPointX(int nIndex);floatGetPointY(int nIndex);intGetPointCount();inline CStringgetLineName(){return this->LineName;}inline voidsetLineName(CString name){this->LineName = name;}inline BOOLgetShowStatus(){return this->IsShow;}inline voidsetShowStatus(BOOL showStatus){this->IsShow = showStatus;}inline COLORREF getLineColor(){return this->LineColor;}inline voidsetLineColor(COLORREF color){this->LineColor = lineColor;};inline intgetLineType(){return this->LineType;}inline voidsetLineType(int lineType){this->LineType = lineType;};inline intgetLineWidth(){return this->LineWidth;}inline voidsetLineWidth(int lineWidth){this->LineWidth = lineWidth;};public:CStringLineName;// 曲线名称BOOL IsShow;// 曲线是否显示COLORREFLineColor;// 颜色int LineType;// 线型 solid,dashint LineWidth;// 线宽 pixelstruct Point{float x;float y;};private:intm_currentSize;// 有效的坐标点数Point *m_pointArrayPtr;// 存储曲线中Point的数组CRITICAL_SECTION g_cs ;};class CAxis{public:struct AxisRangeStruct{// 坐标轴范围float AxisMinValue;// 轴最小值float AxisMaxValue;// 轴最大值};CAxis(COLORREF color = RGB(0,255,0),int style = PS_SOLID, int width = 2,float minValue = 0.0f, float maxValue = 500.0);~CAxis(){}CAxis(const CAxis& axis);CAxis &operator = (const CAxis& axis);inline void SetAxisRange(float minValue=0.0f,float maxValue=500.0f){m_axisRange.AxisMinValue = minValue;m_axisRange.AxisMaxValue = maxValue;}inline float GetAxisRange(){return this->m_axisRange.AxisMaxValue-this->m_axisRange.AxisMinValue;}inline float GetRangeLowerLimit(){return this->m_axisRange.AxisMinValue;}inline float GetRangeUpperLimit(){return this->m_axisRange.AxisMaxValue;}public:BOOL IsShow;// 是否显示坐标轴COLORREFAxisColor;// 颜色int AxisStyle;// 线型int AxisWidth;// 线宽intCoorTextBoxWidth;// 坐标文本框 宽度intCoorTextBoxHeight;// 坐标文本框 高度private:AxisRangeStruct m_axisRange;// 轴代表值的范围};class CPlot :public CStatic{DECLARE_DYNAMIC(CPlot)public:CPlot(void);virtual ~CPlot(void);void Start();void Stop();void AddNewLine(CString name = _T(""),int style = PS_SOLID, COLORREF color = RGB(255,0,0), int iThick = 2);void AddNewPoint(float x,float y,int nLineIndex);//向某一条曲线中添加数据CLine* GetLineByIndex(int nIndex);// 得到第nIndex(从0开始)条曲线的引用CLine* GetLineByName(CString name);// 根据曲线名称获取曲线int GetLineCount();// 获取当前有效曲线个数void SetRate(int nRate);void SetBkColor(COLORREF clrBkColor);CAxis& GetAxisY();CAxis& GetAxisX();private:void RefreshLayout();// 刷新页面布局void RefreshPlot(CDC* pDC);// 刷新控件void DrawBackground(CDC* pDC);// 绘制背景void DrawAxises(CDC* pDC);// 绘制坐标轴void DrawGrids(CDC* pDC);// 绘制网格void DrawLine(CDC* pDC,const CRect& rectZone,const CPoint* pPtr,int nCount);void DrawLines(CDC* pDC);// 绘制全部曲线void DrawLegend(CDC* pDC,CRect& rectZone);// 绘制图例void DrawTile(CDC* pDC,CRect& rectZone);// 绘制标题void ScaleProcess();// 放大操作// 求两个矩形 rect1 和 rect2 的交集矩形CRect IntersectionRect(const CRect& rect1,const CRect& rect2);// 判断一个点是否在矩形上BOOL PointOnRect(const CRect& rect,const CPoint& point );// 判断一个点point是否在矩形rect内部BOOL PointInRect(const CRect& rect,const CPoint& point );// 求两个点之间连线与rect边的交点CPoint IntersectionRectLine(const CRect& rect,const CPoint& inPoint,const CPoint& exPoint );public://floatXMoveStep;// 每次移动X轴增加的值BOOL ShowGrid;// 是否显示网格COLORREFGridColor;// 网格颜色intGridStyle;// 网格线型intGridWidth;// 网格线宽intGridSize;// 网格宽度intShowTextGrap;// 每个多个格显示一个坐标值COLORREFBkGndColor;// 背景颜色intRefreshRate;// 刷新图像周期,msprivate:BOOLm_bAdjustable;// 是否需要自动调整// 布局相关CRectm_rectCtrl; // 控件矩形区域CRectm_rectPlot; // 绘图矩形区域CRectm_rectTitle;// 标题矩形区域CRectm_rectLegend;// 图例矩形区域intm_marginLeft;// 左侧留白宽度intm_marginRight;// 右侧留白宽度intm_marginTop;// 上部留白宽度intm_marginBottom;// 下部留白宽度intm_titleHight;// 标题高度intm_legendHeight;// 图例高度//坐标轴相关CAxis m_axisX;// X 轴CAxis m_axisY; // Y 轴floatm_vppXAxis;// 每个像素代表的X轴值floatm_vppYAxis;// 每个像素点代表的Y轴值// 曲线相关CLine * m_linePtrArray[MaxLinesCount];// 指针数组int validLinesCount;// 有效线的个数// 缩放相关float m_originXLwLmt,m_originXUpLmt;// 已经在自适应情况下的X,Y轴范围float m_originYLwLmt,m_originYUpLmt;CPoint m_startPoint,m_endPoint;// 鼠标左键起止点public:DECLARE_MESSAGE_MAP()afx_msg void OnTimer(UINT nIDEvent);afx_msg void OnPaint();afx_msg BOOL OnEraseBkgnd(CDC* pDC);afx_msg void OnSize(UINT nType, int cx, int cy);afx_msg void OnLButtonDown(UINT nFlag,CPoint point);afx_msg void OnLButtonUp(UINT nFlags, CPoint point);afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);};}
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类)(续)
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类)(续) .
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类)
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类) .
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类)
- MFC的CStatic类(转载)
- MFC+MSChart动态显示曲线
- MFC+MSChart动态显示曲线
- 采用静态文本控件(CStatic)作为的波形曲线控件的显示载体
- 【动态】CStatic显示图片
- MFC动态创建控件--CStatic
- MFC 动态创建超链接 CStatic
- MFC:超链接文本(重绘CStatic)
- MFC中,为自己派生的CStatic控件添加ToolTip
- CStatic类的动态创建,以及使用风格dwStyle的介绍(二)-----CStatic控件的基本使用
- MFC中CStatic控件动态改变
- MFC在CStatic中显示图片
- [MFC]CStatic静态控件类
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类) .
- 用Properties补充hibernate.cfg.xml配置
- 进制转换
- 好友圈
- Bourbaki集合论(1)译者序与作者简介
- MFC 动态曲线 支持缩放 显示图例(CStatic派生类)(续) .
- 将Linux下的Android签名对pk8和pem转换为Eclipse下的签名(keystore)
- javascript根据字符串创建Date对象,在ios和android中行为不一致
- Bourbaki集合论(2)本书的写作方式
- 传说中的数据结构
- 警告: 隐式声明与内建函数 ‘printf’ 不兼容 解决方法(转)
- 基于高通MSM 8x60的I2C驱动终极讲解(1)
- oracle教程之第6章表空间和数据文件的管理
- Bourbaki集合论(3)引论