经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
采用Qt快速绘制多条曲线(折线),跟随鼠标动态显示线上点的值(基于Qt的开源绘图控件QCustomPlot进行二次开发)
来源:cnblogs  作者:先之  时间:2018/12/12 9:54:32  对本文有异议
QCustomPlot是一个开源的基于Qt的第三方绘图库,能够绘制漂亮的2D图形。
QCustomPlot的官方网址:https://www.qcustomplot.com/
从官网下载QCustomPlot的源文件,包括qcustomplot.h和qcustomplot.cpp。
 
本程序的源码下载地址: https://github.com/xiongxw/XCustomPlot.git
 
 
1 自定义鼠标显示跟随类XxwTracer和XxwTraceLine:
XxwTracer用于在图表中显示鼠标所在位置的x,y值
XxwTraceLine用于在图中显示水平或垂直的虚线
头文件XxwTracer.h
  1. #ifndef MYTRACER_H
  2. #define MYTRACER_H
  3. #include <QObject>
  4. #include "qcustomplot.h"
  5. ///
  6. /// \brief The XxwTracer class:在图表中显示鼠标所在位置的x,y值的追踪显示器
  7. ///
  8. class XxwTracer : public QObject
  9. {
  10. Q_OBJECT
  11. public:
  12. enum TracerType
  13. {
  14. XAxisTracer,//依附在x轴上显示x值
  15. YAxisTracer,//依附在y轴上显示y值
  16. DataTracer//在图中显示x,y值
  17. };
  18. explicit XxwTracer(QCustomPlot *_plot, TracerType _type, QObject *parent = Q_NULLPTR);
  19. ~XxwTracer();
  20. void setPen(const QPen &pen);
  21. void setBrush(const QBrush &brush);
  22. void setText(const QString &text);
  23. void setLabelPen(const QPen &pen);
  24. void updatePosition(double xValue, double yValue);
  25. void setVisible(bool m_visible);
  26. protected:
  27. bool m_visible;//是否可见
  28. TracerType m_type;//类型
  29. QCustomPlot *m_plot;//图表
  30. QCPItemTracer *m_tracer;//跟踪的点
  31. QCPItemText *m_label;//显示的数值
  32. QCPItemLine *m_arrow;//箭头
  33. };
  34. ///
  35. /// \brief The XxwCrossLine class:用于显示鼠标移动过程中的鼠标位置的直线
  36. ///
  37. class XxwTraceLine : public QObject
  38. {
  39. public:
  40. enum LineType
  41. {
  42. VerticalLine,//垂直线
  43. HorizonLine, //水平线
  44. Both//同时显示水平和垂直线
  45. };
  46. explicit XxwTraceLine(QCustomPlot *_plot, LineType _type = VerticalLine, QObject *parent = Q_NULLPTR);
  47. ~XxwTraceLine();
  48. void initLine();
  49. void updatePosition(double xValue, double yValue);
  50. void setVisible(bool vis)
  51. {
  52. if(m_lineV)
  53. m_lineV->setVisible(vis);
  54. if(m_lineH)
  55. m_lineH->setVisible(vis);
  56. }
  57. protected:
  58. bool m_visible;//是否可见
  59. LineType m_type;//类型
  60. QCustomPlot *m_plot;//图表
  61. QCPItemStraightLine *m_lineV; //垂直线
  62. QCPItemStraightLine *m_lineH; //水平线
  63. };
  64. #endif // MYTRACER_H

源文件MyTracer.cpp

  1. #include "MyTracer.h"
  2. XxwTracer::XxwTracer(QCustomPlot *_plot, TracerType _type, QObject *parent)
  3. : QObject(parent),
  4. m_plot(_plot),
  5. m_type(_type)
  6. {
  7. m_visible = true;
  8. m_tracer = Q_NULLPTR;// 跟踪的点
  9. m_label = Q_NULLPTR;// 显示的数值
  10. m_arrow = Q_NULLPTR;// 箭头
  11. if (m_plot)
  12. {
  13. QColor clrDefault(Qt::red);
  14. QBrush brushDefault(Qt::NoBrush);
  15. QPen penDefault(clrDefault);
  16. // penDefault.setBrush(brushDefault);
  17. penDefault.setWidthF(0.5);
  18. m_tracer = new QCPItemTracer(m_plot);
  19. m_tracer->setStyle(QCPItemTracer::tsCircle);
  20. m_tracer->setPen(penDefault);
  21. m_tracer->setBrush(brushDefault);
  22. m_label = new QCPItemText(m_plot);
  23. m_label->setLayer("overlay");
  24. m_label->setClipToAxisRect(false);
  25. m_label->setPadding(QMargins(5, 5, 5, 5));
  26. m_label->setBrush(brushDefault);
  27. m_label->setPen(penDefault);
  28. m_label->position->setParentAnchor(m_tracer->position);
  29. // m_label->setFont(QFont("宋体", 8));
  30. m_label->setFont(QFont("Arial", 8));
  31. m_label->setColor(clrDefault);
  32. m_label->setText("");
  33. m_arrow = new QCPItemLine(m_plot);
  34. QPen arrowPen(clrDefault, 1);
  35. m_arrow->setPen(penDefault);
  36. m_arrow->setLayer("overlay");
  37. m_arrow->setClipToAxisRect(false);
  38. m_arrow->setHead(QCPLineEnding::esSpikeArrow);//设置头部为箭头形状
  39. switch (m_type)
  40. {
  41. case XAxisTracer:
  42. {
  43. m_tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
  44. m_tracer->position->setTypeY(QCPItemPosition::ptAxisRectRatio);
  45. m_tracer->setSize(7);
  46. m_label->setPositionAlignment(Qt::AlignTop | Qt::AlignHCenter);
  47. m_arrow->end->setParentAnchor(m_tracer->position);
  48. m_arrow->start->setParentAnchor(m_arrow->end);
  49. m_arrow->start->setCoords(0, 20);//偏移量
  50. break;
  51. }
  52. case YAxisTracer:
  53. {
  54. m_tracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
  55. m_tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
  56. m_tracer->setSize(7);
  57. m_label->setPositionAlignment(Qt::AlignRight | Qt::AlignHCenter);
  58. m_arrow->end->setParentAnchor(m_tracer->position);
  59. m_arrow->start->setParentAnchor(m_label->position);
  60. m_arrow->start->setCoords(-20, 0);//偏移量
  61. break;
  62. }
  63. case DataTracer:
  64. {
  65. m_tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
  66. m_tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
  67. m_tracer->setSize(5);
  68. m_label->setPositionAlignment(Qt::AlignLeft | Qt::AlignVCenter);
  69. m_arrow->end->setParentAnchor(m_tracer->position);
  70. m_arrow->start->setParentAnchor(m_arrow->end);
  71. m_arrow->start->setCoords(20, 0);
  72. break;
  73. }
  74. default:
  75. break;
  76. }
  77. setVisible(false);
  78. }
  79. }
  80. XxwTracer::~XxwTracer()
  81. {
  82. if(m_plot)
  83. {
  84. if (m_tracer)
  85. m_plot->removeItem(m_tracer);
  86. if (m_label)
  87. m_plot->removeItem(m_label);
  88. if (m_arrow)
  89. m_plot->removeItem(m_arrow);
  90. }
  91. }
  92. void XxwTracer::setPen(const QPen &pen)
  93. {
  94. if(m_tracer)
  95. m_tracer->setPen(pen);
  96. if(m_arrow)
  97. m_arrow->setPen(pen);
  98. }
  99. void XxwTracer::setBrush(const QBrush &brush)
  100. {
  101. if(m_tracer)
  102. m_tracer->setBrush(brush);
  103. }
  104. void XxwTracer::setLabelPen(const QPen &pen)
  105. {
  106. if(m_label)
  107. {
  108. m_label->setPen(pen);
  109. m_label->setBrush(Qt::NoBrush);
  110. m_label->setColor(pen.color());
  111. }
  112. }
  113. void XxwTracer::setText(const QString &text)
  114. {
  115. if(m_label)
  116. m_label->setText(text);
  117. }
  118. void XxwTracer::setVisible(bool vis)
  119. {
  120. m_visible = vis;
  121. if(m_tracer)
  122. m_tracer->setVisible(m_visible);
  123. if(m_label)
  124. m_label->setVisible(m_visible);
  125. if(m_arrow)
  126. m_arrow->setVisible(m_visible);
  127. }
  128. void XxwTracer::updatePosition(double xValue, double yValue)
  129. {
  130. if (!m_visible)
  131. {
  132. setVisible(true);
  133. m_visible = true;
  134. }
  135. if (yValue > m_plot->yAxis->range().upper)
  136. yValue = m_plot->yAxis->range().upper;
  137. switch (m_type)
  138. {
  139. case XAxisTracer:
  140. {
  141. m_tracer->position->setCoords(xValue, 1);
  142. m_label->position->setCoords(0, 15);
  143. m_arrow->start->setCoords(0, 15);
  144. m_arrow->end->setCoords(0, 0);
  145. setText(QString::number(xValue));
  146. break;
  147. }
  148. case YAxisTracer:
  149. {
  150. m_tracer->position->setCoords(0, yValue);
  151. m_label->position->setCoords(-20, 0);
  152. // m_arrow->start->setCoords(20, 0);
  153. // m_arrow->end->setCoords(0, 0);
  154. setText(QString::number(yValue));
  155. break;
  156. }
  157. case DataTracer:
  158. {
  159. m_tracer->position->setCoords(xValue, yValue);
  160. m_label->position->setCoords(20, 0);
  161. setText(QString("x:%1,y:%2").arg(xValue).arg(yValue));
  162. break;
  163. }
  164. default:
  165. break;
  166. }
  167. }
  168. XxwTraceLine::XxwTraceLine(QCustomPlot *_plot, LineType _type, QObject *parent)
  169. : QObject(parent),
  170. m_type(_type),
  171. m_plot(_plot)
  172. {
  173. m_lineV = Q_NULLPTR;
  174. m_lineH = Q_NULLPTR;
  175. initLine();
  176. }
  177. XxwTraceLine::~XxwTraceLine()
  178. {
  179. if(m_plot)
  180. {
  181. if (m_lineV)
  182. m_plot->removeItem(m_lineV);
  183. if (m_lineH)
  184. m_plot->removeItem(m_lineH);
  185. }
  186. }
  187. void XxwTraceLine::initLine()
  188. {
  189. if(m_plot)
  190. {
  191. QPen linesPen(Qt::red, 1, Qt::DashLine);
  192. if(VerticalLine == m_type || Both == m_type)
  193. {
  194. m_lineV = new QCPItemStraightLine(m_plot);//垂直线
  195. m_lineV->setLayer("overlay");
  196. m_lineV->setPen(linesPen);
  197. m_lineV->setClipToAxisRect(true);
  198. m_lineV->point1->setCoords(0, 0);
  199. m_lineV->point2->setCoords(0, 0);
  200. }
  201. if(HorizonLine == m_type || Both == m_type)
  202. {
  203. m_lineH = new QCPItemStraightLine(m_plot);//水平线
  204. m_lineH->setLayer("overlay");
  205. m_lineH->setPen(linesPen);
  206. m_lineH->setClipToAxisRect(true);
  207. m_lineH->point1->setCoords(0, 0);
  208. m_lineH->point2->setCoords(0, 0);
  209. }
  210. }
  211. }
  212. void XxwTraceLine::updatePosition(double xValue, double yValue)
  213. {
  214. if(VerticalLine == m_type || Both == m_type)
  215. {
  216. if(m_lineV)
  217. {
  218. m_lineV->point1->setCoords(xValue, m_plot->yAxis->range().lower);
  219. m_lineV->point2->setCoords(xValue, m_plot->yAxis->range().upper);
  220. }
  221. }
  222. if(HorizonLine == m_type || Both == m_type)
  223. {
  224. if(m_lineH)
  225. {
  226. m_lineH->point1->setCoords(m_plot->xAxis->range().lower, yValue);
  227. m_lineH->point2->setCoords(m_plot->xAxis->range().upper, yValue);
  228. }
  229. }
  230. }

 

2 自定义的图表类XCustomPlot
XCustomPlot是基于QCustomPlot二次开发的图表类,在鼠标移动过程中动态显示曲线上点的值。
头文件XCustomPlot.h
  1. #ifndef XCUSTOMPLOT_H
  2. #define XCUSTOMPLOT_H
  3. #include "XxwTracer.h"
  4. #include "qcustomplot.h"
  5. #include <QObject>
  6. #include <QList>
  7.  
  8. class XxwCustomPlot:public QCustomPlot
  9. {
  10. Q_OBJECT
  11. public:
  12. XxwCustomPlot(QWidget *parent = 0);
  13. protected:
  14. virtual void mouseMoveEvent(QMouseEvent *event);
  15. public:
  16. ///
  17. /// \brief 设置是否显示鼠标追踪器
  18. /// \param show:是否显示
  19. ///
  20. void showTracer(bool show)
  21. {
  22. m_isShowTracer = show;
  23. if(m_xTracer)
  24. m_xTracer->setVisible(m_isShowTracer);
  25. foreach (XxwTracer *tracer, m_dataTracers)
  26. {
  27. if(tracer)
  28. tracer->setVisible(m_isShowTracer);
  29. }
  30. if(m_lineTracer)
  31. m_lineTracer->setVisible(m_isShowTracer);
  32. }
  33. ///
  34. /// \brief 是否显示鼠标追踪器
  35. /// \return
  36. ///
  37. bool isShowTracer(){return m_isShowTracer;};
  38. private:
  39. bool m_isShowTracer;//是否显示追踪器(鼠标在图中移动,显示对应的值)
  40. XxwTracer *m_xTracer;//x轴
  41. XxwTracer *m_yTracer;//y轴
  42. QList<XxwTracer *> m_dataTracers;//
  43. XxwTraceLine *m_lineTracer;//直线
  44. };
  45. #endif // XCUSTOMPLOT_H

源文件XCustomPlot.h

  1. #include "XxwCustomPlot.h"
  2. XxwCustomPlot::XxwCustomPlot(QWidget *parent)
  3. :QCustomPlot(parent)
  4. ,m_isShowTracer(false)
  5. ,m_xTracer(Q_NULLPTR)
  6. ,m_yTracer(Q_NULLPTR)
  7. ,m_dataTracers(QList<XxwTracer *>())
  8. ,m_lineTracer(Q_NULLPTR)
  9. {
  10. }
  11. void XxwCustomPlot::mouseMoveEvent(QMouseEvent *event)
  12. {
  13. QCustomPlot::mouseMoveEvent(event);
  14. if(m_isShowTracer)
  15. {
  16. //当前鼠标位置(像素坐标)
  17. int x_pos = event->pos().x();
  18. int y_pos = event->pos().y();
  19. //像素坐标转成实际的x,y轴的坐标
  20. float x_val = this->xAxis->pixelToCoord(x_pos);
  21. float y_val = this->yAxis->pixelToCoord(y_pos);
  22. if(Q_NULLPTR == m_xTracer)
  23. m_xTracer = new XxwTracer(this, XxwTracer::XAxisTracer);//x轴
  24. m_xTracer->updatePosition(x_val, y_val);
  25. if(Q_NULLPTR == m_yTracer)
  26. m_yTracer = new XxwTracer(this, XxwTracer::YAxisTracer);//y轴
  27. m_yTracer->updatePosition(x_val, y_val);
  28. int nTracerCount = m_dataTracers.count();
  29. int nGraphCount = graphCount();
  30. if(nTracerCount < nGraphCount)
  31. {
  32. for(int i = nTracerCount; i < nGraphCount; ++i)
  33. {
  34. XxwTracer *tracer = new XxwTracer(this, XxwTracer::DataTracer);
  35. m_dataTracers.append(tracer);
  36. }
  37. }
  38. else if(nTracerCount > nGraphCount)
  39. {
  40. for(int i = nGraphCount; i < nTracerCount; ++i)
  41. {
  42. XxwTracer *tracer = m_dataTracers[i];
  43. if(tracer)
  44. {
  45. tracer->setVisible(false);
  46. }
  47. }
  48. }
  49. for (int i = 0; i < nGraphCount; ++i)
  50. {
  51. XxwTracer *tracer = m_dataTracers[i];
  52. if(!tracer)
  53. tracer = new XxwTracer(this, XxwTracer::DataTracer);
  54. tracer->setVisible(true);
  55. tracer->setPen(this->graph(i)->pen());
  56. tracer->setBrush(Qt::NoBrush);
  57. tracer->setLabelPen(this->graph(i)->pen());
  58. auto iter = this->graph(i)->data()->findBegin(x_val);
  59. double value = iter->mainValue();
  60. // double value = this->graph(i)->data()->findBegin(x_val)->value;
  61. tracer->updatePosition(x_val, value);
  62. }
  63. if(Q_NULLPTR == m_lineTracer)
  64. m_lineTracer = new XxwTraceLine(this,XxwTraceLine::Both);//直线
  65. m_lineTracer->updatePosition(x_val, y_val);
  66. this->replot();//曲线重绘
  67. }
  68. }

 

 

 

3 使用自定义图表类XCustomPlot

在需要绘图的地方使用,代码如下:

 

  1. m_customPlot = new XxwCustomPlot();
  2. m_customPlot->showTracer(true);
  3. // add title layout element:
  4. m_customPlot->plotLayout()->insertRow(0);
  5. m_customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(m_customPlot, "标题", QFont("黑体", 12, QFont::Bold)));
  6. m_customPlot->legend->setVisible(true);
  7. QFont legendFont = font(); // start out with MainWindow's font..
  8. legendFont.setPointSize(9); // and make a bit smaller for legend
  9. m_customPlot->legend->setFont(legendFont);
  10. m_customPlot->legend->setBrush(QBrush(QColor(255,255,255,230)));
  11. // by default, the legend is in the inset layout of the main axis rect. So this is how we access it to change legend placement:
  12. m_customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop|Qt::AlignCenter);
  13. // make left and bottom axes always transfer their ranges to right and top axes:
  14. connect(m_customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), m_customPlot->xAxis2, SLOT(setRange(QCPRange)));
  15. connect(m_customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), m_customPlot->yAxis2, SLOT(setRange(QCPRange)));
  16. // Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking:
  17. m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
  18. // generate some data:
  19. int nCount = 100;
  20. QVector<double> x(nCount), y0(nCount), y1(nCount); // initialize with entries 0..100
  21. for (int i = 0; i < nCount; ++i)
  22. {
  23. x[i] = i; // x goes from -1 to 1
  24. y0[i] = qSin(i * 10.0f / nCount); //sin
  25. y1[i] = qCos(i * 10.0f / nCount); //cos
  26. }
  27. // create graph and assign data to it:
  28. QPen pen;
  29. int i = 1;
  30. QCPGraph *pGraph = m_customPlot->addGraph();
  31. // m_customPlot->graph(0)->setData(x, y0);
  32. pGraph->setName("sin曲线");
  33. pGraph->setData(x,y0);
  34. pGraph->setPen(QPen(Qt::blue));
  35. pGraph = m_customPlot->addGraph();
  36. // m_customPlot->graph(0)->setData(x, y0);
  37. pGraph->setName("cos曲线");
  38. pGraph->setData(x,y1);
  39. pGraph->setPen(QPen(Qt::darkYellow));
  40. // give the axes some labels:
  41. m_customPlot->xAxis->setLabel("x");
  42. m_customPlot->yAxis->setLabel("y");
  43. // set axes ranges, so we see all data:
  44. // m_customPlot->xAxis->setRange(-1, 1);
  45. // m_customPlot->yAxis->setRange(0, 1);
  46. m_customPlot->rescaleAxes(true);
  47. m_customPlot->replot();

 

4 效果图

 
本程序的源码下载地址: https://github.com/xiongxw/XCustomPlot.git

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号