zoukankan      html  css  js  c++  java
  • QCustomplot使用分享(七) 层(完结)

    一、分层绘制

        一直说要讲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个层,如下代码所示,分别是:背景层、网格层、主层、坐标轴层、图例层和矩形选择区域层。

    1 mLayers.append(new QCPLayer(this, QLatin1String("background")));
    2 mLayers.append(new QCPLayer(this, QLatin1String("grid")));
    3 mLayers.append(new QCPLayer(this, QLatin1String("main")));
    4 mLayers.append(new QCPLayer(this, QLatin1String("axes")));
    5 mLayers.append(new QCPLayer(this, QLatin1String("legend")));
    6 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图层类的部分头文件,代码里的大多数成员变量和成员方法我都给出了注释,大家看看并仔细揣摩一下,应该就基本能理解了。

     1 class QCP_LIB_DECL QCPLayer : public QObject
     2 {
     3     enum LayerMode {//分层绘制原理
     4         lmLogical   ///< Layer is used only for rendering order, and shares paint buffer with all other adjacent logical layers.
     5         , lmBuffered ///< Layer has its own paint buffer and may be replotted individually (see 
    ef replot).
     6     };
     7 
     8     QCPLayer(QCustomPlot* parentPlot, const QString &layerName);
     9     virtual ~QCPLayer();
    10 
    11     // setters:
    12     void setVisible(bool visible);//设置层是否可见
    13     void setMode(LayerMode mode);//绘制时,painter使用模式
    14 
    15     // non-virtual methods:
    16     void replot();//重新绘制层
    17 
    18 protected:
    19     QCustomPlot *mParentPlot;//所在图表
    20     QString mName;//层名称
    21     int mIndex;//层序,决定绘制先后顺序
    22     QList<QCPLayerable*> mChildren;//层中所有元素
    23     bool mVisible;//是否可见标记
    24     LayerMode mMode;//绘制模式标记
    25 
    26     // non-property members:
    27     QWeakPointer<QCPAbstractPaintBuffer> mPaintBuffer;//绘制缓冲区
    28 
    29     // non-virtual methods:
    30     void draw(QCPPainter *painter);//使用painter绘制
    31     void drawToPaintBuffer();//绘制到缓冲区
    32     void addChild(QCPLayerable *layerable, bool prepend);//新增元素
    33     void removeChild(QCPLayerable *layerable);//移除元素
    34 };

    四、自定义层

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

    图1

        实现头文件

     1 class CrossLinePlot : public  QCPLayerable
     2 {
     3     Q_OBJECT
     4 signals :
     5     void DrawCrossLine(const QPoint & pos);
     6 
     7 public:
     8     CrossLinePlot(PlotCallback * basePlot, QCustomPlot * plot);
     9     ~CrossLinePlot();
    10 
    11 public:
    12     QString LayerName() const;//层名称
    13     void SetVisible(bool visible);//设置层是否绘制
    14 
    15     void SetPen(const QPen & pen);/设置十字线画笔
    16 
    17     bool MouseButtonDown() const ;
    18     bool GetLineVisible(QCP::LineState line) const;
    19     void SetLineShow(QCP::LineState lines);//设置线是否显示
    20 
    21     //十字线同步注册接口
    22     bool RegisiterBortherLine(CrossLinePlot * line);
    23     bool UnregisiterBortherLine(CrossLinePlot * line);
    24 
    25 protected:
    26     virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const{};
    27     virtual void draw(QCPPainter * painter);
    28 
    29 private:
    30     void DrawLine(QCPAxis * axis, Qt::Orientation orientation);//画指定方向的坐标轴十字线(严格来说应该是一部分,一条线)
    31     void SyncLinePosition(const QPoint & pos, double x);//同步线位置
    32 
    33 private slots:
    34     void MouseMoveHandle(QMouseEvent * event);
    35 
    36 private:
    37     QScopedPointer<CrossLinePlotPrivate> d_ptr;
    38     static std::vector<CrossLinePlot *> m_BrotherLine;//同步其他十字线
    39 };

        实现文件

      1 std::vector<CrossLinePlot *>CrossLinePlot::m_BrotherLine;
      2 
      3 struct CrossLinePlotPrivate
      4 {
      5     QCP::LineStates m_bIsVisible;
      6     bool m_bLeftButtonPress = false;
      7     double m_dAxisXValue = -1;
      8     QPoint m_MousePoint;
      9     QCPPainter * m_pPainter = nullptr;
     10     QPen m_Pen = QPen(Qt::black, 1, Qt::DashDotLine);
     11     PlotCallback * m_pParentPlot = nullptr;
     12 };
     13 
     14 CrossLinePlot::CrossLinePlot(PlotCallback * basePlot, QCustomPlot * plot)
     15     : QCPLayerable(plot)
     16     , d_ptr(new CrossLinePlotPrivate)
     17 {
     18     d_ptr->m_pParentPlot = basePlot;
     19     mParentPlot->addLayer(LayerName());
     20     
     21     setLayer(LayerName());
     22 
     23     connect(mParentPlot, &QCustomPlot::mousePress, this, [this](QMouseEvent * event){
     24         if (event->button() & Qt::LeftButton)
     25         {
     26             d_ptr->m_bLeftButtonPress = true;
     27         }
     28     });
     29     connect(mParentPlot, &QCustomPlot::mouseRelease, this, [this](QMouseEvent * event){
     30         if (event->button() & Qt::LeftButton)
     31         {
     32             d_ptr->m_bLeftButtonPress = false;
     33         }
     34     });
     35     connect(mParentPlot, &QCustomPlot::mouseMove, this, &CrossLinePlot::MouseMoveHandle);
     36 
     37     QVector<qreal> dashes;
     38     qreal space = 4;
     39     dashes << 3 << space << 9 << space;
     40     d_ptr->m_Pen.setDashPattern(dashes);
     41 }
     42 
     43 CrossLinePlot::~CrossLinePlot()
     44 {
     45 
     46 }
     47 
     48 QString CrossLinePlot::LayerName() const
     49 {
     50     return QStringLiteral("crossline");
     51 }
     52 
     53 void CrossLinePlot::SetVisible(bool visible)
     54 {
     55     QCPLayer * layer = mParentPlot->layer(LayerName());
     56     if (layer)
     57     {
     58         layer->setVisible(visible);
     59     }
     60 }
     61 
     62 void CrossLinePlot::SetPen(const QPen & pen)
     63 {
     64     d_ptr->m_Pen = pen;
     65 }
     66 
     67 bool CrossLinePlot::MouseButtonDown() const
     68 {
     69     return d_ptr->m_bLeftButtonPress;
     70 }
     71 
     72 bool CrossLinePlot::GetLineVisible(QCP::LineState line) const
     73 {
     74     switch (line)
     75     {
     76     case Qt::Horizontal:
     77         return d_ptr->m_bIsVisible.testFlag(QCP::E_Horizontal);
     78         break;
     79     case Qt::Vertical:
     80         return d_ptr->m_bIsVisible.testFlag(QCP::E_Vertical);
     81         break;
     82     }
     83 
     84     return false;
     85 }
     86 
     87 void CrossLinePlot::SetLineShow(QCP::LineState lines)
     88 {
     89     switch (lines)
     90     {
     91     case QCP::E_NULL:
     92         d_ptr->m_bIsVisible = QCP::E_NULL;
     93         break;
     94     case QCP::E_Horizontal:
     95         d_ptr->m_bIsVisible = QCP::E_Horizontal;
     96         break;
     97     case QCP::E_Vertical:
     98         d_ptr->m_bIsVisible = QCP::E_Vertical;
     99         break;
    100     case QCP::E_ALL:
    101         d_ptr->m_bIsVisible = QCP::E_ALL;
    102         break;
    103     }
    104 
    105     if (QCPLayer * layer = mParentPlot->layer(LayerName()))
    106     {
    107         layer->replot();
    108     }
    109 
    110     if (d_ptr->m_bIsVisible == QCP::E_NULL)
    111     {
    112         for (CrossLinePlot * crossline : CrossLinePlot::m_BrotherLine)
    113         {
    114             if (crossline != this)
    115             {
    116                 crossline->SyncLinePosition(QPoint(), d_ptr->m_dAxisXValue);
    117             }
    118         }
    119     }
    120 }
    View Code

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

    五、相关文章

      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. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。 

  • 相关阅读:
    Sublime Text3快捷键大全
    IntelliJ IDEA常用快捷键(Mac)
    shell脚本执行错误 $' ':command not found
    Shell脚本中"command not found"报错处理
    Shell 数值、字符串比较
    Java线程池的构造以及使用
    Host 'xxx' is not allowed to connect to this MySQL server
    Linux下Mysql安装(tar安装)
    Linux下Mysql安装(RPM安装)
    Mac安装Mysql
  • 原文地址:https://www.cnblogs.com/swarmbees/p/6060473.html
Copyright © 2011-2022 走看看