65.9K
CodeProject 正在变化。 阅读更多。
Home

MFC 曲线控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (37投票s)

2004 年 12 月 19 日

4分钟阅读

viewsIcon

104077

downloadIcon

10173

一篇关于曲线控件的文章。

Sample Image - curvectrl.jpg

引言

  • 派生自 CWnd,易于使用
  • 适应绘图矩形的宽度和高度
  • 缩放
  • 鼠标坐标追踪
  • 通过单击鼠标按钮单选/多选
  • 十字线追踪鼠标
  • 通过单击鼠标按钮添加或删除曲线上的点
  • 通过按下鼠标并移动来编辑曲线上点的垂直值
  • 易于移动、偏移或镜像曲线
  • 曲线更改时通知控件的拥有者
  • 拥有者通过消息处理函数的返回值决定是否修改曲线数据
  • Unicode 支持
  • 在 Windows 2000, VC 6.0 下以警告级别 4 编译

背景

最近,我想要在一个应用程序中可视化数据。我搜索了互联网并下载了一些曲线控件。其中大多数都很漂亮并且工作良好,但没有一个能按照我想要的方式工作。在阅读了一些控件的源代码后,我决定开发一个能满足我应用程序需求的曲线控件。

CCurve

CCurve 类,派生自 CObject,用于存储数据和曲线属性。它不执行数据添加或删除。

  • void ShowCurve(BOOL bShow = TRUE);
  • BOOL IsVisible();

    设置/获取可视化状态。

  • void Select(BOOL bSelect = TRUE);
  • BOOL IsSelected

    设置/获取选中状态。

  • BOOL SetCurveName(CString& strName);
  • CString GetCurveName();

    设置/获取曲线名称。

  • void SetCurveColor(COLORREF color);
  • COLORREF GetCurveColor();

    设置/获取曲线的颜色。

  • void SetCurveStyle(int iStyle);
  • int GetCurveStyle();

    设置/获取曲线的样式。

  • void SetCurveWidth(int nWidth);
  • int GetCurveWidth();

    设置/获取曲线的宽度。

  • float Distance(const CPoint& pt1, const CPoint& pt2);

    获取两点之间的距离。

  • BOOL IsPointNearCurve(const CPoint& point, int& iIndex);

    点是否靠近曲线。

CCurveCtrl

  • BOOL Create(const RECT& rect, CWnd* parent, UINT nID,DWORD dwStyle = WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VISIBLE);

    创建控件,其中 rect 表示尺寸。参考 MSDN。

  • int AddCurve(const CString& strName, COLORREF color = RGB(0, 0, 0), int iStyle = PS_SOLID, int nWidth = 1);

    向控件添加一条曲线。

  • BOOL AddData(const CString& strName, float fHori, float fVert);
  • BOOL AddData(CCurve* pCurve, float fHori, float fVert);

    通过索引或对象指针向曲线添加数据。

  • BOOL AddCurveData(const CString& strName, const CArray< float, float >& ArrHori, const CArray< float, float >& ArrVert);

    同时添加一条曲线和数据。

  • CCurve* GetCurve(int iIndex);
  • CCurve* GetCurve(const CString& strName);

    通过其在 CCurveCtrl 中的索引或名称获取曲线对象的指针。

  • int GetIndex(const CCurve* pCurve);

    通过指针获取曲线在 CCurveCtrl 中的索引。

  • BOOL Remove(int index);
  • BOOL Remove(const CString& strName);
  • void RemoveAll();

    移除 CCurveCtrl 中的一条曲线或所有曲线。

  • int GetCurveCount();

    获取曲线的总数。

  • int GetSelectedCount();

    获取选中曲线的数量。

  • void Move(BOOL bLeft);
  • void MovePage(BOOL bLeft);

    将所有曲线和坐标刻度向左或向右移动(不修改数据)。

  • void CurveLeft(CCurve* pCurve, float fLen); void CurveRight(CCurve* pCurve, float fLen);

    将曲线向左或向右移动(会修改曲线的数据)。

  • void MirrorHori(CCurve* pCurve, float fMid);

    水平镜像曲线。

  • void MirrorVert(CCurve* pCurve, float fMid);

    垂直镜像曲线。

  • void Restore();

    显示所有曲线的所有点。

  • BOOL Zoom(BOOL bIn);

    放大(bIn: TRUE)或缩小(bIn: FALSE)。

  • void SetHoriLabel(CString& str);
  • CString GetHoriLabel();

    设置/获取水平轴标签。

  • void SetVertLabel(CString& str);
  • CString GetVertLabel();

    设置/获取垂直轴标签。

  • void ShowCross(BOOL bShow);
  • BOOL IsShowCross();

    是否显示十字线。

  • void SetMargin(const CRect& rect);
  • CRect GetMargin();

    设置/获取用于显示标题等的边距。

  • void EnableEdit(BOOL bEdit);
  • BOOL CanEditCurve();

    是否可以通过鼠标编辑曲线数据。

  • void SetGridLineStyle(int iStyle);
  • int GetGridLineStyle();

    设置/获取背景网格线的样式。

Notifications

如果通过鼠标操作选择了/取消选择了曲线或修改了数据,将向控件的拥有者窗口(父窗口或非父窗口)发送以下通知消息:

  • CVN_MVALUE_ADD - 向曲线添加了一个点。
  • CVN_MVALUE_CHANG - 曲线上的一个点的 Y 值正在改变。
  • CVN_MVALUE_DELETE - 删除了一个点。
  • CVN_CURVE_SELECTED - 选中了一条曲线。
  • CVN_CURVE_CANCELSELECT - 取消选中了一条曲线。
  • CVN_CURVE_SELECTNONE - 取消选中了所有曲线。

结构

typedef struct tagNM_CURVECTRL {
       NMHDR  hdr;      // curve object pointer
       void*  pCurve;   // curve object pointer
       int    iIndex;                                   
       float  fHori;    // horizontal value where cursor is
       float  fVert;    // vertical value where cursor is
} NM_CURVECTRL;

请注意 iIndex 成员:如果发送给拥有者的消息是 CVN_MVALUE_ADDCVN_MVALUE_CHANGECVN_MVALUE_DELETE,则它是曲线上点的索引;如果消息是 CVN_CURVE_SELECTEDCVN_CURVE_CANCELSELECTCVN_CURVE_SELECTNONE,则它是 CCurveCtrl 中曲线的索引。

用法

以下步骤演示如何在基于对话框的应用程序中使用 CCurveCtrl

  1. curvectrl.hcurvectrl.cpp 添加到您的项目中;
  2. 在您的 CDialog 类中添加一个 CCurveCtrl 指针成员
    CCurveCtrl*  m_pCurveCtrl;

    同时添加 include 语句

    #include “CurveCtrl.h”
  3. 在您的对话框构造函数中将 m_pCurveCtrl 设置为 NULL
    m_pCurveCtrl = NULL;

    在您的 resource.h 文件中添加控件的资源 ID,例如:

    #define ID_CURVE_CONTROL   9999

    在您的 CDialog::OnInitDialog() 中,添加如下语句:

    if (NULL == m_pCurveCtrl)
    {
        m_pCurveCtrl = new CCurveCtrl;
        m_pCurveCtrl->Create(CRect(10, 10, 200, 200),    
                             this, 
                             ID_CURVE_CONTROL);    // resorce ID
                             m_pCurveCtrl->SetMargin(CRect(70, 50, 50, 50));
    }
  4. 添加一条曲线和数据如下:
    CString  strName(TestOne);
    m_pCurveCtrl->AddCurve(strName, RGB(255, 0, 0));
    
    for (float f = 0.0f; f < 6.28f; f += 0.1f)
    {
        m_pCurveCtrl->AddData(strTitle, 
                             (m_nCurveCount) * f, 
                             100.f * float(sin(f)));
    }
    m_pCurveCtrl->Invalidate();

    如果您想通过鼠标操作添加/删除或编辑点,必须调用:

    m_pCurveCtrl->EnableEdit(TRUE);

    控件的拥有者将收到通知消息,如果消息的返回值不为 0(大于 0 或小于 0),则编辑或选择/取消选择的尝试将被拒绝。

    例如,要处理 CVN_MVALUE_CHANG 消息,请在您的对话框源文件中添加一个处理程序:

    BEGIN_MESSAGE_MAP(CTestCurveDlg, CDialog)
             ... ...
    ON_NOTIFY(CVN_MVALUE_CHANG, ID_CURVE_CONTROL, OnCurveMouseModify)
    END_MESSAGE_MAP()
     
    // message handle function
    void CTestCurveDlg::OnCurveMouseModify(NMHDR *pNotifyStruct, LRESULT* pResult)
    {
        NM_CURVECTRL* pItem = (NM_CURVECTRL*)pNotifyStruct;
        CCurve* pCurve = (CCurve*)pItem->pCurve;
        CString str;
        str.Format("%s: index: %d, %.1f, %.1f", 
                            pCurve->GetCurveName(), 
                            pItem->iIndex, 
                            pItem->fHori, 
                            pItem->fVert);
        TRACE(str);
        // Uncomment following statement if to reject changing
        // *pResult = 1;
    }

如果您想了解更多信息,请参考示例应用程序 TestCurve。

历史

  • V1.0,2004 年 9 月 19 日

    CCurveCCurveCtrl 首次发布。

© . All rights reserved.