一、分层绘制

一直说要讲2.0.0版本,但总是想把1.3.2版本拿出来比较一下,这篇文章也不例外。QCustomPlot2.0.0beta版本比1.3.2release版本有一个很大的改进那就是分层绘制,所谓分层绘制就是把一张图分几张图来绘制,最后在把这分开的几张图统一绘制到一张图上,比如一张图A,需要分开成3张图B、C和D来绘制,当图A需要重新绘制时,我们一次判断B、C和D是否需要重新绘制,如果不需要绘制的我们直接把图贴到A上,那就很大的减少了重新绘制的时间,而这部分时间其实是没有必要花费的。

二、QCustomPlot的层

QCustomPlot默认提供了6个层,如下代码所示,分别是:背景层、网格层、主层、坐标轴层、图例层和矩形选择区域层。

 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")));
  • 背景层:绘制背景图
  • 网格层:绘制网格线,每一个坐标轴对应一个网格对象
  • 主层:绘制图表
  • 坐标轴层:绘制坐标轴
  • 图例层:绘制图例
  • overlay层:绘制最上层的东西,这一层在1.3.2版本时没有。鼠标选择矩形框在此层绘制。可以参考QCustomplot使用分享(五) 布局文章中图1

实现分层绘制的关键类QCPAbstractPaintBuffer,这是一个抽象基类,通过该类可以拿到一个QCPPainter指针,然后绘制东西的时候,都会绘制在这个指针所指的绘图设备上。QCPAbstractPaintBuffer类一共有3个子类,分别是QCPPaintBufferPixmap、QCPPaintBufferGlPbuffer和QCPPaintBufferGlFbo,这3个类分别使用了不同绘图技术来实现分层绘制。默认使用的是QCPPaintBufferPixmap来绘制,如果想使用QCPPaintBufferGlPbuffer或者QCPPaintBufferGlFbo来绘制,首先要使用setOpenGl接口打开使用opengl开关,然后定义QCP_OPENGL_FBO宏来默认使用QCPPaintBufferGlFbo绘制,或者定义QCP_OPENGL_PBUFFER宏来让默认使用QCPPaintBufferGlPbuffer方式绘制

三、QCPLayer

下图所示是QCPLayer图层类的部分头文件,代码里的大多数成员变量和成员方法我都给出了注释,大家看看并仔细揣摩一下,应该就基本能理解了。

 class QCP_LIB_DECL QCPLayer : public QObject
{
enum LayerMode {//分层绘制原理
lmLogical ///< Layer is used only for rendering order, and shares paint buffer with all other adjacent logical layers.
, lmBuffered ///< Layer has its own paint buffer and may be replotted individually (see \ref replot).
}; QCPLayer(QCustomPlot* parentPlot, const QString &layerName);
virtual ~QCPLayer(); // setters:
void setVisible(bool visible);//设置层是否可见
void setMode(LayerMode mode);//绘制时,painter使用模式 // non-virtual methods:
void replot();//重新绘制层 protected:
QCustomPlot *mParentPlot;//所在图表
QString mName;//层名称
int mIndex;//层序,决定绘制先后顺序
QList<QCPLayerable*> mChildren;//层中所有元素
bool mVisible;//是否可见标记
LayerMode mMode;//绘制模式标记 // non-property members:
QWeakPointer<QCPAbstractPaintBuffer> mPaintBuffer;//绘制缓冲区 // non-virtual methods:
void draw(QCPPainter *painter);//使用painter绘制
void drawToPaintBuffer();//绘制到缓冲区
void addChild(QCPLayerable *layerable, bool prepend);//新增元素
void removeChild(QCPLayerable *layerable);//移除元素
};

四、自定义层

如图1中所示的黑色十字线,就是我在自定义层中绘制的,下面我将我实现的代码贴出来

图1

实现头文件

 class CrossLinePlot : public  QCPLayerable
{
Q_OBJECT
signals :
void DrawCrossLine(const QPoint & pos); public:
CrossLinePlot(PlotCallback * basePlot, QCustomPlot * plot);
~CrossLinePlot(); public:
QString LayerName() const;//层名称
void SetVisible(bool visible);//设置层是否绘制 void SetPen(const QPen & pen);/设置十字线画笔 bool MouseButtonDown() const ;
bool GetLineVisible(QCP::LineState line) const;
void SetLineShow(QCP::LineState lines);//设置线是否显示 //十字线同步注册接口
bool RegisiterBortherLine(CrossLinePlot * line);
bool UnregisiterBortherLine(CrossLinePlot * line); protected:
virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const{};
virtual void draw(QCPPainter * painter); private:
void DrawLine(QCPAxis * axis, Qt::Orientation orientation);//画指定方向的坐标轴十字线(严格来说应该是一部分,一条线)
void SyncLinePosition(const QPoint & pos, double x);//同步线位置 private slots:
void MouseMoveHandle(QMouseEvent * event); private:
QScopedPointer<CrossLinePlotPrivate> d_ptr;
static std::vector<CrossLinePlot *> m_BrotherLine;//同步其他十字线
};

实现文件

 std::vector<CrossLinePlot *>CrossLinePlot::m_BrotherLine;

 struct CrossLinePlotPrivate
{
QCP::LineStates m_bIsVisible;
bool m_bLeftButtonPress = false;
double m_dAxisXValue = -;
QPoint m_MousePoint;
QCPPainter * m_pPainter = nullptr;
QPen m_Pen = QPen(Qt::black, , Qt::DashDotLine);
PlotCallback * m_pParentPlot = nullptr;
}; CrossLinePlot::CrossLinePlot(PlotCallback * basePlot, QCustomPlot * plot)
: QCPLayerable(plot)
, d_ptr(new CrossLinePlotPrivate)
{
d_ptr->m_pParentPlot = basePlot;
mParentPlot->addLayer(LayerName()); setLayer(LayerName()); connect(mParentPlot, &QCustomPlot::mousePress, this, [this](QMouseEvent * event){
if (event->button() & Qt::LeftButton)
{
d_ptr->m_bLeftButtonPress = true;
}
});
connect(mParentPlot, &QCustomPlot::mouseRelease, this, [this](QMouseEvent * event){
if (event->button() & Qt::LeftButton)
{
d_ptr->m_bLeftButtonPress = false;
}
});
connect(mParentPlot, &QCustomPlot::mouseMove, this, &CrossLinePlot::MouseMoveHandle); QVector<qreal> dashes;
qreal space = ;
dashes << << space << << space;
d_ptr->m_Pen.setDashPattern(dashes);
} CrossLinePlot::~CrossLinePlot()
{ } QString CrossLinePlot::LayerName() const
{
return QStringLiteral("crossline");
} void CrossLinePlot::SetVisible(bool visible)
{
QCPLayer * layer = mParentPlot->layer(LayerName());
if (layer)
{
layer->setVisible(visible);
}
} void CrossLinePlot::SetPen(const QPen & pen)
{
d_ptr->m_Pen = pen;
} bool CrossLinePlot::MouseButtonDown() const
{
return d_ptr->m_bLeftButtonPress;
} bool CrossLinePlot::GetLineVisible(QCP::LineState line) const
{
switch (line)
{
case Qt::Horizontal:
return d_ptr->m_bIsVisible.testFlag(QCP::E_Horizontal);
break;
case Qt::Vertical:
return d_ptr->m_bIsVisible.testFlag(QCP::E_Vertical);
break;
} return false;
} void CrossLinePlot::SetLineShow(QCP::LineState lines)
{
switch (lines)
{
case QCP::E_NULL:
d_ptr->m_bIsVisible = QCP::E_NULL;
break;
case QCP::E_Horizontal:
d_ptr->m_bIsVisible = QCP::E_Horizontal;
break;
case QCP::E_Vertical:
d_ptr->m_bIsVisible = QCP::E_Vertical;
break;
case QCP::E_ALL:
d_ptr->m_bIsVisible = QCP::E_ALL;
break;
} if (QCPLayer * layer = mParentPlot->layer(LayerName()))
{
layer->replot();
} if (d_ptr->m_bIsVisible == QCP::E_NULL)
{
for (CrossLinePlot * crossline : CrossLinePlot::m_BrotherLine)
{
if (crossline != this)
{
crossline->SyncLinePosition(QPoint(), d_ptr->m_dAxisXValue);
}
}
}
}

有兴趣的同学可以自行看实现文件,代码都不难理解

五、相关文章

  QCustomplot使用分享(一) 能做什么事

  QCustomplot使用分享(二) 源码解读

  QCustomplot使用分享(三) 图

  QCustomplot使用分享(四) QCPAbstractItem

  QCustomplot使用分享(五) 布局

  QCustomplot使用分享(六) 坐标轴和网格线

六、总结

这是QCustomPlot的第7篇文章了,按照我第二篇文章描述的那样,从QCustomplot使用分享(二) 源码解读、QCustomplot使用分享(三) 图   折线、参数曲线、蜡烛图、柱状图、面积图、QCustomplot使用分享(四) QCPAbstractItem、QCustomplot使用分享(五) 布局、QCustomplot使用分享(六) 坐标轴  网格线和QCustomplot使用分享(七) 层等这几个方面对QCustomPlot做了一个分析,其实还有很多细节我没有说到的地方。

虽然我使用QCustomPlot库的时间不长,但是用了3天的时间我把QCustomPlot的使用或者说是心得记录了下来,这几篇文章在写的过程中,也是自我回忆、自我重新理解的一个过程,说实话写完这几篇文章我还是收获挺大的,最起码能连贯的把这个源码库融合起来,现在在回想起这个库我就会觉得脑子里已经有了一个大概的图,也可以说是一幅画,基本的功能模块大体掌握,如果这时候给我一个需求,那我可能会更好的理解这个需求,更好的去在合适的地方更合理的完成这个需求。

七、示例下载

  基于QCustomPlot1.3.2的二次开发

  基于QCustomPlot2.0.0的二次开发

如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! 

 

很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。

QCustomplot使用分享(七) 层(完结)的更多相关文章

  1. QCustomplot使用分享(八) 绘制图表-加载cvs文件

    目录 一.概述 二.效果图 三.源码讲解 1.源码结构 2.头文件 3.移动游标 4.设置坐标轴矩形个数 5.添加图表数据 6.设置折线图类型 6.其他函数 四.测试方式 1.测试工程 2.测试文件 ...

  2. QCustomplot使用分享(九) 绘制图表-多功能游标

    目录 一.概述 二.效果图 三.源码讲解 1.源码结构 2.头文件 3.添加游标 4.监测移动 5.移动游标 6.其他函数 四.测试方式 1.测试工程 2.测试文件 3.测试代码 五.相关文章 六.总 ...

  3. QCustomplot使用分享(二) 源码解读

    一.头文件概述 从这篇文章开始,我们将正式的进入到QCustomPlot的实践学习中来,首先我们先来学习下QCustomPlot的类图,如果下载了QCustomPlot源码的同学可以自己去QCusto ...

  4. QCustomplot使用分享(五) 布局

    一.历史对比 关于QCPLayoutElement这个元素的讲解之前,我想先对1.3.2release版本和2.0.0beta版本的该元素做以简单的对比介绍,首先,1.3.2release版本时,鼠标 ...

  5. TCP/IP 网络精讲:OSI七层模型(第二课)

    内容简介 1.前言 2.第一部分第二课:互联网的创立,OSI七层模型 3.第一部分第三课预告:OSI第一层,连接你的机器 前言 PS:昨天做了课程大纲之后,发现这个坑挖得有点大.不过既然挖了,岂有不跳 ...

  6. 【阿里聚安全·安全周刊】双十一背后的“霸下-七层流量清洗”系统| 大疆 VS “白帽子”,到底谁威胁了谁?

    关键词:霸下-七层流量清洗系统丨大疆 VS "白帽子"丨抢购软件 "第一案"丨企业安全建设丨Aadhaar 数据泄漏丨朝鲜APT组织Lazarus丨31款违规A ...

  7. ISO七层模型详解

    ISO七层模型详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在我刚刚接触运维这个行业的时候,去面试时总是会做一些面试题,笔试题就是看一个运维工程师的专业技能的掌握情况,这个很 ...

  8. 一张非常强大的OSI七层模型图解。。。

    源自http://www.colasoft.com.cn/download/protocols_map.php,非常适合小白入门,后面罗列出来方便大家浏览记忆...(不经意间看到的,分享一下) OSI ...

  9. 如何生动形象、切中要点地讲解 OSI 七层模型和两主机传输过程

    作者:繁星亮与鲍包包链接:https://www.zhihu.com/question/24002080/answer/31817536来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

随机推荐

  1. openSUSE 11 上的配置可以Xmanager远程桌面

    openSUSE 11 上的配置(适用于默认图形环境为KDE的Linux): 1.配置KDM. openSUSE 11的默认图形环境为KDE,虽然可以同时安装GDM和KDM,但默认只启动了KDM.所以 ...

  2. SQL SERVER 内存学习系列(一)

    最近帮客户解决发布订阅的问题时,突然遇到这样一个问题发布订阅中报下面的错误,另外执行alter table 操作时也会报错 : 问题很奇怪发布订阅和CLR有什么关系?memtoleave内存是个啥?回 ...

  3. 关于实现一个基于文件持久化的EventStore的核心构思

    大家知道enode框架的架构是基于ddd+event sourcing的思想.我们持久化的不是聚合根的最新状态,而是聚合根产生的领域事件.最近我在思考如何实现一个基于文件的eventstore.目标有 ...

  4. WebApi系列~按需序列化字段~Hot

    回到目录 起初只是一个想法,一次讨论,一个设想,但相信一定可以实现,具体的事情是这样的,有个对外的API项目,它为一些终端设备提供数据,如手机,平板,PC,当然你也可以说它为很多平台提供数据win32 ...

  5. 知方可补不足~sqlserver中的几把锁~续

    回到目录 之前写过相关的文章,对脏读,不可重复读,幻读都做了相当的研究,而今天在程序中又出现了这个问题,即当一条数据被update时,另一个线程同时发起了读的操作,这对于序列化级别的事务是不被允许的, ...

  6. 更新日志 - BugHD iOS 客户端上线

    中秋.十一长假归来,"满血复活"的我们做了 fir.im 和 BugHD 的优化更新:) BugHD 新增功能 1.iOS 客户端上线 BugHD iOS 客户端上线了,你可以随时 ...

  7. JDBC操作数据库,第一:jsp插入mysql数据库,坎坷摸索分享

    JSP连接数据库,坎坷摸索了好久,现在终于做好了,分享一下,希望对更多热爱编程学习的人有所帮助!!!谢谢 第一:首先准备的就是已经安装好Mysql,这里不做多叙述,百度可以做到. 然后在mysql数据 ...

  8. QQ表情动图,增加写博客的乐趣

    QQ表情动图,增加写博客的乐趣 body{margin:0px;}

  9. 技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

    1.前言 作为应用层开发人员,接触最多的网络协议通常都是传输层的TCP(与之同处一层的另一个重要协议是UDP协议),但对于IP协议,对于应用程序员来说更多的印象还是IP地址这个东西,再往深一点也就很难 ...

  10. 浏览器加载和渲染html的顺序

    前阵子,在组内给大家做了一次关于“浏览器加载和渲染HTML的顺序”的分享,这里再总结一下吧. AD:干货来了,不要等!WOT2015 北京站演讲PPT开放下载! 1.浏览器加载和渲染html的顺序 浏 ...