MFC 曲线控件






4.90/5 (37投票s)
2004 年 12 月 19 日
4分钟阅读

104077

10173
一篇关于曲线控件的文章。
引言
- 派生自
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_ADD
、CVN_MVALUE_CHANGE
或 CVN_MVALUE_DELETE
,则它是曲线上点的索引;如果消息是 CVN_CURVE_SELECTED
、CVN_CURVE_CANCELSELECT
或 CVN_CURVE_SELECTNONE
,则它是 CCurveCtrl
中曲线的索引。
用法
以下步骤演示如何在基于对话框的应用程序中使用 CCurveCtrl
- 将 curvectrl.h 和 curvectrl.cpp 添加到您的项目中;
- 在您的
CDialog
类中添加一个CCurveCtrl
指针成员CCurveCtrl* m_pCurveCtrl;
同时添加
include
语句#include “CurveCtrl.h”
- 在您的对话框构造函数中将
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)); }
- 添加一条曲线和数据如下:
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 日
CCurve
,CCurveCtrl
首次发布。