QCustomplot使用分享(七) 層(完結)

1、分層繪製

    一直說要講2.0.0版本,但老是想把1.3.2版本拿出來比較一下,這篇文章也不例外。QCustomPlot2.0.0beta版本比1.3.2release版本有一個很大的改進那就是分層繪製,所謂分層繪製就是把一張圖分幾張圖來繪製,最後在把這分開的幾張圖統一繪製到一張圖上,好比一張圖A,須要分開成3張圖B、C和D來繪製,當圖A須要從新繪製時,咱們一次判斷B、C和D是否須要從新繪製,若是不須要繪製的咱們直接把圖貼到A上,那就很大的減小了從新繪製的時間,而這部分時間實際上是沒有必要花費的。html

2、QCustomPlot的層

    QCustomPlot默認提供了6個層,以下代碼所示,分別是:背景層、網格層、主層、座標軸層、圖例層和矩形選擇區域層。app

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方式繪製ide

3、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 \ref 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 };

4、自定義層

    如圖1中所示的黑色十字線,就是我在自定義層中繪製的,下面我將我實現的代碼貼出來post

圖1this

    實現頭文件url

 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 };

    實現文件spa

  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

    有興趣的同窗能夠自行看實現文件,代碼都不難理解.net

5、相關文章

  QCustomplot使用分享(一) 能作什麼事指針

  QCustomplot使用分享(二) 源碼解讀

  QCustomplot使用分享(三) 圖

  QCustomplot使用分享(四) QCPAbstractItem

  QCustomplot使用分享(五) 佈局

  QCustomplot使用分享(六) 座標軸和網格線

6、總結

    這是QCustomPlot的第7篇文章了,按照我第二篇文章描述的那樣,從QCustomplot使用分享(二) 源碼解讀、QCustomplot使用分享(三) 圖   折線、參數曲線、蠟燭圖、柱狀圖、面積圖、QCustomplot使用分享(四) QCPAbstractItem、QCustomplot使用分享(五) 佈局、QCustomplot使用分享(六) 座標軸  網格線和QCustomplot使用分享(七) 層等這幾個方面對QCustomPlot作了一個分析,其實還有不少細節我沒有說到的地方。

    雖然我使用QCustomPlot庫的時間不長,可是用了3天的時間我把QCustomPlot的使用或者說是心得記錄了下來,這幾篇文章在寫的過程當中,也是自我回憶、自我從新理解的一個過程,說實話寫完這幾篇文章我仍是收穫挺大的,最起碼能連貫的把這個源碼庫融合起來,如今在回想起這個庫我就會以爲腦子裏已經有了一個大概的圖,也能夠說是一幅畫,基本的功能模塊大致掌握,若是這時候給我一個需求,那我可能會更好的理解這個需求,更好的去在合適的地方更合理的完成這個需求。

7、示例下載

  基於QCustomPlot1.3.2的二次開發

  基於QCustomPlot2.0.0的二次開發

 

若是您以爲文章不錯,不妨給個 打賞,寫做不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。 

相關文章
相關標籤/搜索