MFC high-speed-charting控件使用(添加垂直游标,两个控件的联动)

应用场景

最近参与的一个项目中涉及到在一个对话框中添加两个high-speed-charting控件,在两个控件中添加dragline游标,并要求:

  1. 光标不可越过其左右游标且不能拖到控件外;
  2. 拖动其中一个控件中的dragline游标时,另一个控件中对应游标也移动。

控件的基础使用

参考了大神尘中远的博客TeeChart替代品,MFC下好用的高速绘图控件-(Hight-Speed Charting),详细讲述了如何添加控件,并在控件中添加坐标轴和画线。

Hight-Speed Charting自带对chart的缩放,左键拖动控制缩放,右键拖动chart,但由于添加dragline游标后也需要左键拖动,有冲突,所以本文中禁用了其缩放(调用yourChartCtrlName.SetZoomEnabled(false);),当然,也可以尝试将缩放移到鼠标滚轮,但由于本人对此部分不太熟悉,希望能有人加以改进


添加游标前的准备工作

1.添加所需的函数,变量
(1)ChartDragLineCursor.h中声明函数及变量

public:CChartCtrl* GetParent();void SetPosition(double dPosition);void SetWidth(int NewWidth)double GetValuePosition()bool GetDragged();double minx,maxx;
private:long last_lPosition;int m_iLineWidth;

(2)以下代码为ChartDragLineCursor.cpp中几个函数的实现(要先在.h文件的类中声明该函数)

 CChartCtrl* CChartDragLineCursor::GetParent() { return m_pParentCtrl; }void CChartDragLineCursor::SetPosition(double dPosition){m_lPosition = m_pRelatedAxis->ValueToScreen(dPosition);}void CChartDragLineCursor::SetWidth(int NewWidth) {m_iLineWidth = NewWidth;m_pParentCtrl->RefreshCtrl();}double CChartDragLineCursor::GetValuePosition() {return m_pRelatedAxis->ScreenToValue(m_lPosition);}bool CChartDragLineCursor::GetDragged() { return m_bDragged; }

同时需要修改OnDraw()函数中的第一行为

 CPen NewPen(PS_SOLID, m_iLineWidth, m_colCursor);

接着修改OnMouseMove()函数:

 //OnMouseMove中修改以下部分if (m_pRelatedAxis->IsHorizontal()){if (m_bDragged) {m_lPosition = max(m_pRelatedAxis->ValueToScreen(minx), mousePoint.x);m_lPosition = min(m_pRelatedAxis->ValueToScreen(maxx), m_lPosition);XVal = m_pRelatedAxis->ScreenToValue(m_lPosition);}}else{m_lPosition = mousePoint.y;YVal = m_pRelatedAxis->ScreenToValue(m_lPosition);}CursorMoved(XVal, YVal);

这样,就可以调用几个set函数,在创建一条draglinecursor时设置其颜色、宽度、初始位置等。(颜色设置函数已有,可直接调用,例如:SetColor(RGB(255,0,0));)

(3)ChartCtrl.h中声明函数与变量

 //x_max存储控件x轴的最大刻度,需要与坐标轴的真实最大刻度保持一致int x_max = 600;//get cursors获取所有的cursorstd::map<unsigned, CChartCursor*> GetCursors() {return m_mapCursors;}

若需更改或初始化x轴刻度最大值,则如下,需要对真实刻度和x_max同时设置

 m_chartctrl.x_max = x_size;m_chartctrl.pBottomAxis->SetMinMax(1, x_size);

2.需要为dragline游标注册绑定一个监听器,这个监听器继承已有的CChartCursorListener(在ChartCursor.h中声明),并需要实现其中的纯虚函数OnCursorMoved,实现如下:

 class CCustomCursorListener : public CChartCursorListener{public:virtual void OnCursorMoved(CChartCursor *pCursor, double xValue, double yValue){CChartDragLineCursor* dragCursor = (CChartDragLineCursor*)pCursor;CChartCtrl* m_parent = dragCursor->GetParent();map<unsigned, CChartCursor*> m_cursors = m_parent->GetCursors();int cursorsCount = m_cursors.size();if (dragCursor->GetCursorId() % cursorsCount == 0) {dragCursor->maxx = max(m_cursors[dragCursor->GetCursorId() + 1]->GetValuePosition() - 5.0, 1.0);dragCursor->minx = 1.0;if(dragCursor->GetDragged()) vectorToSavePositionOfCursors[dragCursor->GetCursorId() % cursorsCount] = xValue;}else if (dragCursor->GetCursorId() % cursorsCount == cursorsCount - 1) {dragCursor->maxx = m_parent->x_max;dragCursor->minx = m_cursors[dragCursor->GetCursorId() - 1]->GetValuePosition() + 5.0;if (dragCursor->GetDragged()) vectorToSavePositionOfCursors[dragCursor->GetCursorId() % cursorsCount] = xValue;}else {dragCursor->maxx = m_cursors[dragCursor->GetCursorId() + 1]->GetValuePosition() - 5.0;dragCursor->minx = m_cursors[dragCursor->GetCursorId() - 1]->GetValuePosition() + 5.0;if (dragCursor->GetDragged()) vectorToSavePositionOfCursors[dragCursor->GetCursorId() % cursorsCount] = xValue;}}void GetHwnd(HWND hwnd){m_hwnd = hwnd;}private:HWND m_hwnd;};

添加dragline游标

调用以下函数添加垂直方向dragline

yourChartCtrlName.CreateDragLineCursor(CChartCtrl::BottomAxis)

注:我批量添加的方法:

 //所有游标归父对话框同一起标号,所以先对一个控件中的集中创建,再创建另一个控件中的游标//m_ChartCtrl是存储chartctrl控件指针的数组for (int i = 0; i < chartNum; i++) {for (int j = 0; j < cursorNum; j++) {m_ChartCtrl[i]->CreateDragLineCursor(CChartCtrl::BottomAxis);}}//假如每个中创建6个,那么这样创建的游标,m_ChartCtrl[0]中的ID分别为0-5,m_ChartCtrl[1]中的分别为6-11

以下代码为给游标注册一个监听器(若有多个cursor,分别给他们注册不同的监听器)

 for (int i = 0; i < chartNum; i++) {for(int i = 0; i < cursorNum; i++){m_ChartCtrl[i]->CCustomCursorListener* m_listener = new CCustomCursorListener();m_listener->GetHwnd(this->GetSafeHwnd());m_cursor->RegisterListener(m_listener);}}

下图为添加游标后的效果图


多控件联动

1.为dragline添加伙伴游标(在ChartDragLineCursor.h中)

 //friend draglineCChartDragLineCursor* friendline;

2.使dragline能与伙伴游标联动(在ChartDragLineCursor.cpp中)

 //修改Draw函数void CChartDragLineCursor::Draw(CDC* pDC)
{CPen NewPen(PS_SOLID, m_iLineWidth, m_colCursor);CPen* pOldPen = pDC->SelectObject(&NewPen);CRect plottingRect = m_pParentCtrl->GetPlottingRect();if (m_pRelatedAxis->IsHorizontal()){pDC->MoveTo(m_lPosition, plottingRect.top);pDC->LineTo(m_lPosition, plottingRect.bottom);}else{pDC->MoveTo(plottingRect.left, m_lPosition);pDC->LineTo(plottingRect.right, m_lPosition);}pDC->SelectObject(pOldPen);NewPen.DeleteObject();if (m_bDragged && friendline) {friendline->m_lPosition = friendline->m_pRelatedAxis->ValueToScreen(this->m_pRelatedAxis->ScreenToValue(this->m_lPosition));if (abs(friendline->last_lPosition - friendline->m_lPosition) > 0.2) {friendline->GetParent()->Invalidate(true);friendline->last_lPosition = friendline->m_lPosition;}}
}
 //修改OnMouseMove函数void CChartDragLineCursor::OnMouseMove(CPoint mousePoint){bool friendline_dragged = false;if (friendline) {friendline_dragged = friendline->m_bDragged;}if ((!m_bDragged) && (!friendline_dragged))return;double XVal = 0;double YVal = 0;if (m_pRelatedAxis->IsHorizontal()){if (m_bDragged) {m_lPosition = max(m_pRelatedAxis->ValueToScreen(minx), mousePoint.x);m_lPosition = min(m_pRelatedAxis->ValueToScreen(maxx), m_lPosition);XVal = m_pRelatedAxis->ScreenToValue(m_lPosition);}}else{m_lPosition = mousePoint.y;YVal = m_pRelatedAxis->ScreenToValue(m_lPosition);}CursorMoved(XVal, YVal);}

3.在使用时将两个控件中的游标互相赋为伙伴游标

 //将两个控件中的多个for (int i = 0; i < cursorNum; i++) {cursors[0][i]->friendline = cursors[1][i];cursors[1][i]->friendline = cursors[0][i];}

最终效果如下:

拖动一个控件中的一个游标,另一个中对应位置的游标会同步移动,并实时更新游标位置记录。

我发布了一个chartctrl控件版本,包括我自己封装的一个类,PaintChart,调用其中的函数即可完成快速初始化控件,画线,拟合曲线,以及放置并联动光标等功能,由于主要面向的是我们一个项目,可扩展性不太好,但修改起来还是比较容易的,需要的可以下载看一看

目前代码中有很多冗余或者质量较低的部分,而且画出的光标有轻微的闪烁,下一步需要继续改进一下。
欢迎联系我跟我交流。

MFC high-speed-charting控件使用(添加垂直游标,两个控件的联动)相关推荐

  1. MFC中动态创建控件以及添加事件响应

    本文实例讲述了MFC中动态创建控件以及事件响应实现方法,分享给大家供大家参考.具体实现方法如下: 动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的. 一.创建动态 ...

  2. MFC中动态创建控件及添加消息响应的方法实例

    动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的. 一.创建动态控件: 为了对照,我们先来看一下静态控件的创建. 放置静态控件时必须先建立一个容器,一般是对话框, ...

  3. asp.net panel 加html,ASP.NET 页面中动态增加的控件、添加事件

    要求:页面上有一个Add按钮,每点击一次该按钮,页面上动态创建一个WebPartZone! 提醒:WebPartZone只能在OnInit或之前才能创建,否则报异常! 大家都知道,按钮的点击事件是在R ...

  4. mfc在两个控件间连线

    新建一个对话框工程: 添加2个按钮,ID分别为IDC_ONE.IDC_TWO,再添加一个 GO!按钮: 为 GO!按钮添加单击消息处理函数: 单击代码: void CTwotwoDlg::OnButt ...

  5. ASP.NET开发:在用户控件中添加属性

    在WEB开发中,可重用的代码我们可以把它写成一个通用模块供需要的地方来引用.本文就是介绍在ASP.NET的web编程时,如何在用户控件中添加属性,实现这种方法:举例说明详解. 在WEB开发中经常有一些 ...

  6. 在 GridView 控件中添加一列复选框51

    简介 在前面的教程中 , 我们学习了如何为 GridView 控件添加一列 单选 按钮来选择一个特定的记录.当用户被限制最多只能从网格中选中一项时,一列单选按钮是一个非常恰当的用户界面.然而,有时我们 ...

  7. C# 系统应用之ListView控件 (三).添加ContextMenuStrip右键菜单打开删除文件

    在前面讲述过使用TreeView控件和ListView控件显示磁盘目录信息,但仅仅是显示信息是不够的,我们还需要具体的操作.在"个人电脑使用历史痕迹"项目中我还需要添加" ...

  8. 转——C# DataGridView控件 动态添加新行

    DataGridView控件在实际应用中非常实用,特别需要表格显示数据时.可以静态绑定数据源,这样就自动为DataGridView控件添加相应的行.假如需要动态为DataGridView控件添加新行, ...

  9. 使用控件设计窗体 上 布局主窗体 添加标签与文本框控件

    使用控件设计窗体 上 布局主窗体 添加标签与文本框控件 项目目标 所需控件 窗体基本设置 新建窗体 设置背景图片 设置平铺模式 设置icon 设置文字 修改名称 直接修改类名 标签控件与文本框控件 标 ...

最新文章

  1. 解决win7不能上网的问题
  2. 访中科曙光智能计算技术总监许涛:重新认识面向未来的AI服务器和云计算中心...
  3. 怎样解决ASP图片上传漏洞的方法
  4. 37.使用PreResultListener实现回调
  5. 2019年第十届蓝桥杯国赛B组试题B-质数拆分-01背包问题+素数筛选
  6. 2.1线性表的类型定义
  7. 【README1】动态规划之解题思路
  8. Spring Boot基础学习笔记11:Spring MVC
  9. 大数据平台架构包括哪些方面
  10. 主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生...
  11. 统一认证 java_java统一身份认证系统
  12. html网页图片下方空隙太大,网页制作中图片上下间为什么会有空隙?解决办法...
  13. 基于Foolnltk的《三体》文本命名实体分析
  14. 推特难民涌入「长毛象」!这个小众社交平台一夜爆红
  15. 服务器远程登录用户在哪查看,RAKsmart VNC用户登录信息在哪查看?
  16. 这个高仿小米商城项目太惊艳了
  17. BAT批处理批量修改文件后缀名
  18. 全国各地DNS地址详细列表
  19. 12306抢票算法居然被曝光了,居然这么简单
  20. 摄像头的数据输出格式

热门文章

  1. 通过微博名查看id html,微博id在哪里查看?
  2. 14.[保护模式]TSS任务段
  3. MySQL运动会管理系统_运动会管理系统(JAVA,JSP,SERVLET,SQLSERVER)
  4. 《iPad开发从入门到精通》——6.5节地图信息
  5. 不完全免疫算法简介HEIA--AIS学习笔记2
  6. 树莓派下使用USB摄像头
  7. centos 7, 8 的区别
  8. 一文了解各大数据库查询语言(Gremlin vs Cypher vs nGQL操作篇
  9. linux输入ll命令各个字段的含义
  10. hdu2094 c语言