MFC 动态曲线 支持缩放 显示图例(CStatic派生类)(续) .

来源:互联网 发布:还珠格格知画扮演者 编辑:程序博客网 时间:2024/05/16 11:45
前面的文章已经介绍了在MFC环境下绘制动态曲线的方法(双缓冲绘图)和基本的步骤(分三步),以及用到的库函数。下面就介绍一下布局和鼠标响应事件,这里我做过一点

小小的创新(至少我没有看到有前人做过,哈哈。。)

(一)关于布局

   一般的绘制动态曲线的过程就是,先把坐标定下来,什么地方画轴,什么地方写字。当需要变更布局时,就有点麻烦了。当然也可以定义一些手动设置的属性来控制。本文借助

CSS的布局思想,创建了一些CRect的对象,每个对象绑定一个绘图元素。例如,

[html] view plaincopyprint?
  1. CRect m_rectCtrl;  // 获取整个控件的区域  
  2. CRect m_rectPlot;  // 用于绘制曲线的区域  
  3. CRect m_rectTitle; // 绘制标题的区域  
  4. CRect m_rectLegend;  // 绘制图例的区域  

坐标轴、曲线、图例等元素都在指定的CRect绘制。同时定义一些属性用来控制几个CRect的相对位置,这样要改变布局只需要修正他们的相对位置即可,呵呵。。

(二)关于缩放

   由于真实系统中各点坐标都是浮点数,而MFC中CPoint的坐标是整数。所以一般是向直线中加入一个新的点是,都按一定的公式转化为CPoint的整数坐标值。但这样对缩放操作

不是很方便。本项目中,为每个直线对象(CLine类的对象,CLine是自定义的,它有很多和该线相关的属性,如线型、线宽、颜色等,同时包含一个点的数组,点的坐标都是float

型的)内部的点都以float型存储,在要绘制曲线时,临时申请一个CPoint型的数组,用于绘图。

  同时每个坐标轴(Axis类,也是自定义类)都带有指示该坐标轴表示范围的属性。在计算上述CPoint的值时,需要联合CLine和Axis两个属性值确定。当在进行缩放时,只需要改

变坐标轴的范围即可。当在进行下一次绘图时,计算的CPoint坐标值会自动改变。从而实现了缩放。

  但这也会带来一个问题,刚才已经说过,绘制曲线实在m_rectPlot矩形框中的。缩放时必然会有点的坐标超出这个矩形。出现如下的情况:

 

 

要解决这个问题可不容易,最简单的方法是,如果某一个点的某一维坐标值超出矩形,则就将其限定在矩形的那个边上,但这样图像看起来有点奇怪。

复杂的方法是,遍历所有的点,判断每个点是否在矩形内部,分多种情况

①如果上一点和该点都在矩形内部,则从上一个点LineTo()当前的点;

②如果上一个点不在矩形内,当前的点在矩形内部,或者当前的点不在矩形内部,而上一个点在矩形内部,则需要计算这两个点的连线与矩形的交点,并绘制

一条从交点到矩形内部那个点的直线;

③如果上一个点和当前的点都不在矩形内部,则什么也不做。

这里还需要自己写几个函数,

[cpp] view plaincopyprint?
  1. // 求两个矩形 rect1 和 rect2 的交集矩形   
  2. CRect IntersectionRect(const CRect& rect1,const CRect& rect2);  
  3. // 判断一个点是否在矩形上   
  4. BOOL PointOnRect(const CRect& rect,const CPoint& point );  
  5. // 判断一个点point是否在矩形rect内部   
  6. BOOL PointInRect(const CRect& rect,const CPoint& point );     
  7. // 求两个点之间连线与rect边的交点   
  8. CPoint IntersectionRectLine(const CRect& rect,const CPoint& inPoint,const CPoint& exPoint );  

这里面就有点算法的内容,当然我用的算法肯定不是最好的,还望广大网友指正,尤其是最后一个函数,情况有点复杂

    缩放后如何恢复呢?在这种结构下就非常简单了,用一个数据记录最初始的坐标轴范围,当鼠标双击时,将当前的坐标轴范围更改为最原始的那个范围,按照缩放的原理,自

然复原了。


(三)关于鼠标响应事件

   要实现更复杂的功能,离不开响应鼠标事件。当然“CStatic控件响应鼠标” ,Google一下可以得到完美解答,这里就顺便提及一下。也是最简单的方法。

①在“资源视图”中,找到你用于绘制曲线的CStatic控件,将属性“Notify”改为True;

②编写的CStatic继承类的.h文件中添加

[cpp] view plaincopyprint?
  1. DECLARE_MESSAGE_MAP()  
  2. afx_msg void OnLButtonDown(UINT nFlag,CPoint point);  
  3. afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
  4. afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);  

③在CStatic继承类的实现的.cpp文件中添加消息映射:

[cpp] view plaincopyprint?
  1. BEGIN_MESSAGE_MAP(CPlot, CStatic)  
  2.     ON_WM_LBUTTONDOWN()  
  3.     ON_WM_LBUTTONUP()  
  4.     ON_WM_LBUTTONDBLCLK()  
  5. END_MESSAGE_MAP()  

并实现上述三个函数。

OK,大功告成,MFC下绘制动态曲线的任务就完成啦,下面贴出.h文件,供大家参考,欢迎讨论。

完整资源请到 上一篇博文给出的地址进行下载。

[cpp] view plaincopyprint?
  1. #pragma once   
  2.   
  3. #include <vector>   
  4.   
  5. using namespace std;  
  6.   
  7. namespace RealtimeCurve{  
  8.     const int MaxPointsCount = 512; // 曲线最大存储点数  
  9.     const int MaxLinesCount = 10;   // 控件容纳最大曲线个数  
  10.   
  11.     class CLine  
  12.     {  
  13.     public:  
  14.         CLine(CString name=_T(""),  
  15.             int lineStyle = PS_SOLID,   
  16.             COLORREF lineColor = RGB(255,0,0),  
  17.             int lineWidth = 2);  
  18.         CLine(const CLine& nLine);  
  19.         CLine& operator = (const CLine& nLine);  
  20.         ~CLine();  
  21.           
  22.         _declspec(property(get = getLineName,put = setLineName))    CString lineName;  
  23.         _declspec(property(get = getShowStatus,put = setShowStatus)) BOOL showStatus;  
  24.         _declspec(property(get = getLineColor,put = setLineColor)) COLORREF lineColor;  
  25.         _declspec(property(get = getLineType,put = setLineType)) int lineType;  
  26.         _declspec(property(get = getLineWidth,put = setLineWidth)) int lineWidth;  
  27.   
  28.         void    AddPoint(float x, float y);  
  29.         float   GetPointX(int nIndex);  
  30.         float   GetPointY(int nIndex);  
  31.         int     GetPointCount();  
  32.           
  33.         inline CString  getLineName()               {   return this->LineName;   }  
  34.         inline void     setLineName(CString name)   {   this->LineName = name;   }  
  35.         inline BOOL     getShowStatus()             {   return this->IsShow; }  
  36.         inline void     setShowStatus(BOOL showStatus){ this->IsShow = showStatus;   }  
  37.         inline COLORREF getLineColor()              {   return this->LineColor;}  
  38.         inline void     setLineColor(COLORREF color){   this->LineColor = lineColor; };  
  39.         inline int      getLineType()               {   return this->LineType;}  
  40.         inline void     setLineType(int lineType)   {   this->LineType = lineType;   };  
  41.         inline int      getLineWidth()              {   return this->LineWidth;}  
  42.         inline void     setLineWidth(int lineWidth) {   this->LineWidth = lineWidth; };  
  43.   
  44.     public:  
  45.         CString     LineName;       // 曲线名称  
  46.         BOOL        IsShow;         // 曲线是否显示  
  47.         COLORREF    LineColor;      // 颜色  
  48.         int         LineType;       // 线型 solid,dash  
  49.         int         LineWidth;      // 线宽 pixel  
  50.         struct Point{  
  51.             float x;  
  52.             float y;  
  53.         };  
  54.     private:          
  55.         int         m_currentSize;      // 有效的坐标点数  
  56.         Point *     m_pointArrayPtr;    // 存储曲线中Point的数组  
  57.         CRITICAL_SECTION g_cs ;  
  58.     };  
  59.   
  60.     class CAxis  
  61.     {  
  62.       
  63.     public:       
  64.         struct AxisRangeStruct{     // 坐标轴范围  
  65.             float AxisMinValue;     // 轴最小值  
  66.             float AxisMaxValue;     // 轴最大值  
  67.         };  
  68.           
  69.         CAxis(COLORREF color = RGB(0,255,0),  
  70.                 int style = PS_SOLID,   
  71.                 int width = 2,  
  72.                 float minValue = 0.0f,   
  73.                 float maxValue = 500.0);  
  74.         ~CAxis(){   }  
  75.         CAxis(const CAxis& axis);  
  76.         CAxis &operator = (const CAxis& axis);  
  77.   
  78.         inline void SetAxisRange(float minValue=0.0f,float maxValue=500.0f){  
  79.             m_axisRange.AxisMinValue = minValue;  
  80.             m_axisRange.AxisMaxValue = maxValue;  
  81.         }  
  82.         inline float GetAxisRange(){      
  83.             return this->m_axisRange.AxisMaxValue-this->m_axisRange.AxisMinValue;  
  84.         }  
  85.         inline float GetRangeLowerLimit()   {   return this->m_axisRange.AxisMinValue;   }  
  86.         inline float GetRangeUpperLimit()   {   return this->m_axisRange.AxisMaxValue;   }  
  87.               
  88.     public:  
  89.         BOOL        IsShow;         // 是否显示坐标轴  
  90.         COLORREF    AxisColor;      // 颜色  
  91.         int         AxisStyle;      // 线型  
  92.         int         AxisWidth;      // 线宽         
  93.   
  94.         int         CoorTextBoxWidth;   // 坐标文本框 宽度  
  95.         int         CoorTextBoxHeight;  // 坐标文本框 高度  
  96.     private:  
  97.         AxisRangeStruct m_axisRange;    // 轴代表值的范围  
  98.     };  
  99.   
  100.     class CPlot :  
  101.         public CStatic  
  102.     {  
  103.         DECLARE_DYNAMIC(CPlot)  
  104.   
  105.     public:  
  106.         CPlot(void);  
  107.         virtual ~CPlot(void);  
  108.   
  109.         void Start();  
  110.         void Stop();  
  111.       
  112.           
  113.         void AddNewLine(CString name = _T(""),  
  114.                     int style = PS_SOLID,   
  115.                     COLORREF color = RGB(255,0,0),   
  116.                     int iThick = 2);  
  117.         void AddNewPoint(float x,float y,int nLineIndex);   //向某一条曲线中添加数据  
  118.         CLine* GetLineByIndex(int nIndex);  // 得到第nIndex(从0开始)条曲线的引用  
  119.         CLine* GetLineByName(CString name); // 根据曲线名称获取曲线  
  120.         int    GetLineCount();              // 获取当前有效曲线个数  
  121.   
  122.         void SetRate(int nRate);  
  123.         void SetBkColor(COLORREF clrBkColor);  
  124.         CAxis& GetAxisY();  
  125.         CAxis& GetAxisX();  
  126.   
  127.     private:  
  128.         void RefreshLayout();           // 刷新页面布局  
  129.         void RefreshPlot(CDC* pDC);     // 刷新控件  
  130.         void DrawBackground(CDC* pDC);  // 绘制背景  
  131.         void DrawAxises(CDC* pDC);      // 绘制坐标轴  
  132.         void DrawGrids(CDC* pDC);       // 绘制网格  
  133.         void DrawLine(CDC* pDC,const CRect& rectZone,const CPoint* pPtr,int nCount);  
  134.         void DrawLines(CDC* pDC);       // 绘制全部曲线  
  135.         void DrawLegend(CDC* pDC,CRect& rectZone);      // 绘制图例  
  136.         void DrawTile(CDC* pDC,CRect& rectZone);        // 绘制标题  
  137.   
  138.         void ScaleProcess();        // 放大操作  
  139.           
  140.         // 求两个矩形 rect1 和 rect2 的交集矩形   
  141.         CRect IntersectionRect(const CRect& rect1,const CRect& rect2);  
  142.         // 判断一个点是否在矩形上   
  143.         BOOL PointOnRect(const CRect& rect,const CPoint& point );  
  144.         // 判断一个点point是否在矩形rect内部   
  145.         BOOL PointInRect(const CRect& rect,const CPoint& point );     
  146.         // 求两个点之间连线与rect边的交点   
  147.         CPoint IntersectionRectLine(const CRect& rect,const CPoint& inPoint,const CPoint& exPoint );  
  148.     public:  
  149.         //float     XMoveStep;      // 每次移动X轴增加的值  
  150.   
  151.         BOOL        ShowGrid;       // 是否显示网格  
  152.         COLORREF    GridColor;      // 网格颜色  
  153.         int         GridStyle;      // 网格线型  
  154.         int         GridWidth;      // 网格线宽  
  155.         int         GridSize;       // 网格宽度       
  156.         int         ShowTextGrap;   // 每个多个格显示一个坐标值  
  157.         COLORREF    BkGndColor;     // 背景颜色  
  158.         int         RefreshRate;    // 刷新图像周期,ms  
  159.     private:  
  160.         BOOL    m_bAdjustable;      // 是否需要自动调整  
  161.         // 布局相关   
  162.         CRect   m_rectCtrl;                 // 控件矩形区域  
  163.         CRect   m_rectPlot;                 // 绘图矩形区域  
  164.         CRect   m_rectTitle;                // 标题矩形区域  
  165.         CRect   m_rectLegend;               // 图例矩形区域  
  166.         int     m_marginLeft;               // 左侧留白宽度  
  167.         int     m_marginRight;              // 右侧留白宽度  
  168.         int     m_marginTop;                // 上部留白宽度  
  169.         int     m_marginBottom;             // 下部留白宽度  
  170.         int     m_titleHight;               // 标题高度  
  171.         int     m_legendHeight;             // 图例高度  
  172.         //  坐标轴相关   
  173.         CAxis m_axisX;      // X 轴  
  174.         CAxis m_axisY;      // Y 轴   
  175.   
  176.         float       m_vppXAxis;     // 每个像素代表的X轴值  
  177.         float       m_vppYAxis;     // 每个像素点代表的Y轴值  
  178.         // 曲线相关   
  179.         CLine * m_linePtrArray[MaxLinesCount];  // 指针数组  
  180.         int validLinesCount;                    // 有效线的个数  
  181.         // 缩放相关   
  182.         float m_originXLwLmt,m_originXUpLmt;    // 已经在自适应情况下的X,Y轴范围  
  183.         float m_originYLwLmt,m_originYUpLmt;      
  184.         CPoint m_startPoint,m_endPoint;         // 鼠标左键起止点  
  185.   
  186.     public:  
  187.         DECLARE_MESSAGE_MAP()  
  188.         afx_msg void OnTimer(UINT nIDEvent);  
  189.         afx_msg void OnPaint();  
  190.         afx_msg BOOL OnEraseBkgnd(CDC* pDC);  
  191.         afx_msg void OnSize(UINT nType, int cx, int cy);  
  192.         afx_msg void OnLButtonDown(UINT nFlag,CPoint point);  
  193.         afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
  194.         afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);      
  195.     };  
  196. }  


0 0
原创粉丝点击