QcustomPlot的理解

  • 说明
    • QCustomPlot类
    • 类图
    • 布局
    • 数据关系
    • 结束语

说明

这篇主要介绍QCustomPlo的整体实现思路,理解是非常重要的。

QCustomPlot类


QCustomPlot类是直接面向用户来使用。具有默认的图层展示。
可以参见其源码:

QCustomPlot::QCustomPlot(QWidget *parent) :QWidget(parent),xAxis(0),yAxis(0),xAxis2(0),yAxis2(0),legend(0),mBufferDevicePixelRatio(1.0), // will be adapted to primary screen belowmPlotLayout(0),mAutoAddPlottableToLegend(true),mAntialiasedElements(QCP::aeNone),mNotAntialiasedElements(QCP::aeNone),mInteractions(0),mSelectionTolerance(8),mNoAntialiasingOnDrag(false),mBackgroundBrush(Qt::white, Qt::SolidPattern),mBackgroundScaled(true),mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),mCurrentLayer(0),mPlottingHints(QCP::phCacheLabels|QCP::phImmediateRefresh),mMultiSelectModifier(Qt::ControlModifier),mSelectionRectMode(QCP::srmNone),mSelectionRect(0),mOpenGl(false),mMouseHasMoved(false),mMouseEventLayerable(0),mMouseSignalLayerable(0),mReplotting(false),mReplotQueued(false),mOpenGlMultisamples(16),mOpenGlAntialiasedElementsBackup(QCP::aeNone),mOpenGlCacheLabelsBackup(true)
{setAttribute(Qt::WA_NoMousePropagation);setAttribute(Qt::WA_OpaquePaintEvent);setFocusPolicy(Qt::ClickFocus);setMouseTracking(true);QLocale currentLocale = locale();currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);setLocale(currentLocale);
#ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
#  ifdef QCP_DEVICEPIXELRATIO_FLOATsetBufferDevicePixelRatio(QWidget::devicePixelRatioF());
#  elsesetBufferDevicePixelRatio(QWidget::devicePixelRatio());
#  endif
#endifmOpenGlAntialiasedElementsBackup = mAntialiasedElements;mOpenGlCacheLabelsBackup = mPlottingHints.testFlag(QCP::phCacheLabels);// create initial layers:mLayers.append(new QCPLayer(this, QLatin1String("background")));mLayers.append(new QCPLayer(this, QLatin1String("grid")));mLayers.append(new QCPLayer(this, QLatin1String("main")));mLayers.append(new QCPLayer(this, QLatin1String("axes")));mLayers.append(new QCPLayer(this, QLatin1String("legend")));mLayers.append(new QCPLayer(this, QLatin1String("overlay")));updateLayerIndices();setCurrentLayer(QLatin1String("main"));layer(QLatin1String("overlay"))->setMode(QCPLayer::lmBuffered);// create initial layout, axis rect and legend:mPlotLayout = new QCPLayoutGrid;mPlotLayout->initializeParentPlot(this);mPlotLayout->setParent(this); // important because if parent is QWidget, QCPLayout::sizeConstraintsChanged will call QWidget::updateGeometrymPlotLayout->setLayer(QLatin1String("main"));QCPAxisRect *defaultAxisRect = new QCPAxisRect(this, true);mPlotLayout->addElement(0, 0, defaultAxisRect);xAxis = defaultAxisRect->axis(QCPAxis::atBottom);yAxis = defaultAxisRect->axis(QCPAxis::atLeft);xAxis2 = defaultAxisRect->axis(QCPAxis::atTop);yAxis2 = defaultAxisRect->axis(QCPAxis::atRight);legend = new QCPLegend;legend->setVisible(false);defaultAxisRect->insetLayout()->addElement(legend, Qt::AlignRight|Qt::AlignTop);defaultAxisRect->insetLayout()->setMargins(QMargins(12, 12, 12, 12));defaultAxisRect->setLayer(QLatin1String("background"));xAxis->setLayer(QLatin1String("axes"));yAxis->setLayer(QLatin1String("axes"));xAxis2->setLayer(QLatin1String("axes"));yAxis2->setLayer(QLatin1String("axes"));xAxis->grid()->setLayer(QLatin1String("grid"));yAxis->grid()->setLayer(QLatin1String("grid"));xAxis2->grid()->setLayer(QLatin1String("grid"));yAxis2->grid()->setLayer(QLatin1String("grid"));legend->setLayer(QLatin1String("legend"));// create selection rect instance:mSelectionRect = new QCPSelectionRect(this);mSelectionRect->setLayer(QLatin1String("overlay"));setViewport(rect()); // needs to be called after mPlotLayout has been createdreplot(rpQueuedReplot);
}

QcustomPlot类中包含其他功能模块,来进行布局和绘制。需要理解各个类的关系,其中QCPLayer类继承于QObject类。QCPLayout是布局的基类。各个图表的绘制建立在坐标轴之上,其中坐标轴的绘制建立在布局窗口之上,一个QCustomPlot可以有多个布局窗口,一个布局窗口可以包含多个样式坐标轴。

类图


QCPLayerable是所有可绘制对象的基类,包括网格,坐标轴,装饰器,图标。关于具体的实现可以参见官网例子。

布局

先上一张官网图片

其中最外层是顶层窗口的边缘,每个布局和相邻的窗口都有默认的间隔(每个布局都有自己的索引,布局中可以插入子布局),同样布局中的元素也有默认的间隔(每个元素都有自己的索引)。正是由于源码这种灵活的实现,使得我们可以在布局上有极大的自主权。

数据关系

说一下,它内部是如何实现的。每个图表都有自己对应的数据类:
比如QCPGraph内部维护着QCPGraghData的数组。当我们进行绘制的时候,取出其中的数据进行每个点的绘制。同样当我们想获取某个区域,或者某个像素点的的数据时,可以先进行像素点到坐标轴(参见QCPAxis类函数)的数据转换,然后通过相应图表的接口函数获取当前区域或者点的值。如下

QCPDataSelection selection = graph->selection();double sum = 0;foreach (QCPDataRange dataRange, selection.dataRanges()){QCPGraphDataContainer::const_iterator begin = graph->data()->at(dataRange.begin()); // get range begin iterator from indexQCPGraphDataContainer::const_iterator end = graph->data()->at(dataRange.end()); // get range end iterator from indexfor (QCPGraphDataContainer::const_iterator it=begin; it!=end; ++it){// iterator "it" will go through all selected data points, as an example, we calculate the value averagesum += it->value;}}double average = sum/selection.dataPointCount();

获取选中区域的数据,首先要设置选中属性。这个逻辑可以写在鼠标弹起事件中。

QCPGraphDataContainer::const_iterator it = graph->data()->constEnd();QVariant details;if (graph->selectTest(QPoint(123, 456), false, &details)) // QPoint could be e.g. event->pos() of a mouse event{QCPDataSelection dataPoints = details.value<QCPDataSelection>();if (dataPoints.dataPointCount() > 0)it = graph->data()->at(dataPoints.dataRange().begin());}// iterator "it" now carries the data point at pixel coordinates (123, 456), or constEnd if no data point was hit.

这个逻辑可以写在鼠标点击事件和鼠标弹起事件中

结束语

如何想要绘制出比较好看的图,还是要图层元素的属性有详细的了解。
附上官网
文档

QCustomPlot使用详解(二)相关推荐

  1. 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  2. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  3. PopUpWindow使用详解(二)——进阶及答疑

    相关文章: 1.<PopUpWindow使用详解(一)--基本使用> 2.<PopUpWindow使用详解(二)--进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...

  4. Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  5. linux 进程间通信 dbus-glib【实例】详解二(下) 消息和消息总线(ListActivatableNames和服务器的自动启动)(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  6. linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  7. Android Gradle 自定义Task详解二:进阶

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78523958 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  8. Android Loader 异步加载详解二:探寻Loader内部机制

    Android Loader 异步加载详解二:探寻Loader内部机制 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/7025991 ...

  9. EXT核心API详解(二)-Array/Date/Function/Number/String

    EXT核心API详解(二)-Array/Date/Function/Number/String Array类 indexOf( Object o )  Number object是否在数组中,找不到返 ...

最新文章

  1. 博士买房后发现被坑,于是写万字论文维权,网友:维权界的天花板...
  2. LeCun:现在还没有真正的AI系统,机器与生物系统差远了
  3. 初探团队基于session的探索性测试
  4. 微信自动回复和自动抢红包实现原理(二):自动回复
  5. openvc学习笔记(4)——两种方法在没有环境下运行程序
  6. Jenkins持续集成 之 Jenkins安装
  7. javascript/jquery获取图片的原始大小
  8. Python学习入门基础教程(learning Python)--5.7 Python文件数据记录存储与处理
  9. pandas合并数据集-【老鱼学pandas】
  10. ocx控件注册和解除注册
  11. 据我所知目前就只飞秋表情库
  12. 如何编辑修改PDF文字
  13. java fifo lifo_一日一技:Python队列:FIFO 和 LIFO
  14. GPIB编程控件指令
  15. Oracle删除数据非常慢
  16. 【广告算法工程师入门 32】从直播答题,跳一跳,抢红包等产品策略扯到用户受益商业变现
  17. vue调取电脑摄像头实现拍照功能
  18. HTML5期末大作业:在线音乐网站设计——简洁bootstrap响应式社交音乐网站模板html整站(38页) HTML+CSS+JavaScript
  19. 【转载】犀利哥:无法犀利的人生
  20. 大数据—Hive(一)_ 基本概念

热门文章

  1. 怎样解决电感啸叫声?
  2. typescript浅拷贝与深拷贝
  3. 应届生必看的2020互联网求职指南!
  4. 计算机一级常用函数英语翻译,用一个Excel公式实现中英文快速翻译-excel公式
  5. 北京钢铁学校计算机99,首钢工学院
  6. Python编写坦克大战(新增无敌模式)
  7. android 进度图表,Android 常用效果(各种进度条,酷炫loading动画,火箭升空,撒花以及趋势图)...
  8. LA3516 Exploring Pyramids
  9. 函数 获得所有英文字母
  10. C#毕业设计——基于C#+asp.net+SQL server的通用作业批改系统设计与实现(毕业论文+程序源码)——作业批改系统