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


一、概述

    前邊已經寫了5篇對QCustomPlot的講解,看過上述的幾篇文章后,基本就能做一些簡單的使用了,但是如果想要做到高度的控制圖表,那么坐標軸將是很重要的一部分,因為坐標軸就是圖表的一個參考系,沒有了參考系那么一切都是天方夜譚。關於QCustomPlot的坐標軸我還是會按照之前的套路,首先對比1.3.2版本和2.0.0beta版本,然后在深入的去分析坐標軸使用。

二、歷史版本對比

    首先我需要和大家伙說明下,我個人覺着在QCustomPlot的定制過程中,坐標軸定制算是比較困難的,因為坐標軸如果要定制的話,那就是坐標軸的刻度需要自己計算,如果這個時候相關的業務邏輯也影響坐標軸的計算,那么就更難計算了,呵呵。。。或許大家伙可能也不會遇到這些問題,有興趣的同學也可以自己思考下。

  1.3.2版本 2.0.0版本
坐標軸
1、QCPAxis:坐標軸類,所有坐標軸功能都在這一個類總實現,包括:刻度計算和繪制文本
2、默認刻度自動計算,負責計算大刻度和小刻度
3、如果需要外部計算刻度則處理ticksRequest請求
1、QCPAxis:坐標軸類,所有坐標軸功能都在這一個類總實現,包括:刻度計算和繪制文本
2、默認刻度自動計算,負責計算大刻度和小刻度
3、如果需要外部計算刻度則處理ticksRequest請求

表1 1.3.2版本和2.0.0版本坐標軸比較

    下面我將針對2.0.0版本的坐標軸刻度計算來加以解釋,為了方便起見,我只解釋QCPAxisTicker這個坐標軸刻度計算基類,因為QCPAxis坐標軸默認使用的就是這個類,其余的坐標軸刻度計算類比如QCPAxisTickerDateTime、QCPAxisTickerTime、QCPAxisTickerFixed、QCPAxisTickerText、QCPAxisTickerPi和QCPAxisTickerLog等都是根據不同業務需求,重新實現了vitural相關方法。

三、坐標軸

1、QCPAxis,如下是QCPAxis的頭文件,我從中刪除了大量不需要注釋的部分,但是很是剩下許多,為了寫注釋方便所以我沒有把代碼折疊,有興趣的同學可以閱讀下其中的中文注釋,其實這個類僅僅是用來連接計算和繪制坐標軸的一個類,也可以說是暴露給使用者的一個導出類。

  1 class QCP_LIB_DECL QCPAxis : public QCPLayerable
  2 {
  3     enum AxisType {//坐標軸類型,在一個坐標軸矩形QCPAxisRect中包含左、上、右和下四條坐標軸
  4         atLeft = 0x01  ///< <tt>0x01</tt> Axis is vertical and on the left side of the axis rect
  5         , atRight = 0x02  ///< <tt>0x02</tt> Axis is vertical and on the right side of the axis rect
  6         , atTop = 0x04  ///< <tt>0x04</tt> Axis is horizontal and on the top side of the axis rect
  7         , atBottom = 0x08  ///< <tt>0x08</tt> Axis is horizontal and on the bottom side of the axis rect
  8     };
  9     enum LabelSide {//坐標軸刻度上的文本的位置,刻度線里or外
 10         lsInside    ///< Tick labels will be displayed inside the axis rect and clipped to the inner axis rect
 11         , lsOutside  ///< Tick labels will be displayed outside the axis rect
 12     };
 13     enum ScaleType {//坐標軸類型,直線or對數線
 14         stLinear       ///< Linear scaling
 15         , stLogarithmic ///< Logarithmic scaling with correspondingly transformed axis coordinates (possibly also \ref setTicker to a \ref QCPAxisTickerLog instance).
 16     };
 17     enum SelectablePart {/坐標軸可以被選中的部分
 18         spNone = 0      ///< None of the selectable parts
 19         , spAxis = 0x001  ///< The axis backbone and tick marks
 20         , spTickLabels = 0x002  ///< Tick labels (numbers) of this axis (as a whole, not individually)
 21         , spAxisLabel = 0x004  ///< The axis label
 22     };
 23 
 24     explicit QCPAxis(QCPAxisRect *parent, AxisType type);
 25     virtual ~QCPAxis();
 26   //所有的get接口已經被我刪除  看到對應的set接口,get接口的含義就不言而喻
 27     // setters:
 28     Q_SLOT void setScaleType(QCPAxis::ScaleType type);//設置坐標軸類型  直線or對數
 29     Q_SLOT void setRange(const QCPRange &range);//設置坐標軸范圍
 30     void setRange(double lower, double upper); 33     void setTicker(QSharedPointer<QCPAxisTicker> ticker);//設置坐標軸計算刻度類,該參數是一個shared型智能指針,因此可以被多個坐標軸來同時使用
 31     void setTicks(bool show);//是否顯示坐標軸,如果不顯示坐標軸,那么網格線也就沒有啦,因為沒有了坐標軸刻度
 32     void setTickLabels(bool show);//是否顯示坐標軸文本
 33     void setTickLabelPadding(int padding);//設置坐標走文本距離坐標軸線距離
 34     void setTickLabelFont(const QFont &font);//設置文本字體
 35     void setTickLabelColor(const QColor &color);//設置文本顏色
 36     void setTickLabelRotation(double degrees);//設置文本角度
 37     void setTickLabelSide(LabelSide side);//設置文本在刻度線里or外
 38     void setNumberFormat(const QString &formatCode);//設置文本格式
 39     void setNumberPrecision(int precision);//設置文本精度
 40     void setTickLength(int inside, int outside = 0);//設置大刻度高度
 41     void setTickLengthIn(int inside);//設置大刻度在里邊長度
 42     void setTickLengthOut(int outside);//設置大刻度在外邊長度
 43     void setSubTicks(bool show);//設置是否顯示小刻度
 44     void setSubTickLength(int inside, int outside = 0);//設置小刻度高度
 45     void setSubTickLengthIn(int inside);//設置小刻度在坐標軸線里邊長度
 46     void setSubTickLengthOut(int outside);//設置小刻度在坐標軸線外邊長度
 47     void setBasePen(const QPen &pen);//設置基礎線畫筆  基礎線是零線,即可以認為是坐標軸刻度為0的線
 48     void setTickPen(const QPen &pen);//設置大刻度畫筆
 49     void setSubTickPen(const QPen &pen);//設置小刻度畫筆
 50     void setLabelFont(const QFont &font);//設置坐標軸名稱字體畫筆
 51     void setLabelColor(const QColor &color);//設置坐標軸名稱字體顏色
 52     void setLabel(const QString &str);//設置坐標軸名稱文本
 53     void setLabelPadding(int padding);//設置坐標軸名稱文本距離坐標軸刻度線距離
 54     void setPadding(int padding);//設置坐標軸距離邊界距離
 55     void setOffset(int offset);//設置偏移量
 56     void setSelectedTickLabelFont(const QFont &font);//設置選中刻度文本時字體
 57     void setSelectedLabelFont(const QFont &font);//設置選中坐標軸名稱時字體
 58     void setSelectedTickLabelColor(const QColor &color);//選中刻度文本時顏色
 59     void setSelectedLabelColor(const QColor &color);//選中坐標軸名稱時顏色
 60     void setSelectedBasePen(const QPen &pen);//選中基礎線時畫筆
 61     void setSelectedTickPen(const QPen &pen);//選中大刻度時畫筆
 62     void setSelectedSubTickPen(const QPen &pen);//選中小刻度時畫筆
 63     Q_SLOT void setSelectableParts(const QCPAxis::SelectableParts &selectableParts);//設置能選中項的類型
 64     Q_SLOT void setSelectedParts(const QCPAxis::SelectableParts &selectedParts);
 65     void setLowerEnding(const QCPLineEnding &ending);//設置坐標軸小刻度端樣式
 66     void setUpperEnding(const QCPLineEnding &ending);//坐標軸大刻度端樣式 73 
 67     // non-property methods:
 68     Qt::Orientation orientation() const { return mOrientation; }//坐標軸朝向
 69     int pixelOrientation() const { return rangeReversed() != (orientation() == Qt::Vertical) ? -1 : 1; }
 70     void moveRange(double diff);//移動坐標軸
 71     void scaleRange(double factor);//按比例因子縮放
 72     void scaleRange(double factor, double center);//按范圍縮放 81     void rescale(bool onlyVisiblePlottables = false);//重新適配坐標軸范圍
 73     double pixelToCoord(double value) const;//像素到坐標軸坐標系
 74     double coordToPixel(double value) const;//坐標軸坐標系到像素 85     QList<QCPAbstractPlottable*> plottables() const;//所有的圖
 75     QList<QCPGraph*> graphs() const;//所有的折線
 76     QList<QCPAbstractItem*> items() const;//所有的示意項 92 
 77 protected:
 78     AxisType mAxisType;//坐標軸類型
 79     QCPAxisRect *mAxisRect;//坐標軸所在矩形116 
 80     // non-property members:
 81     QCPGrid *mGrid;//網格120     QSharedPointer<QCPAxisTicker> mTicker;//坐標軸刻度計算類
 82     QVector<double> mTickVector;//大刻度
 83     QVector<QString> mTickVectorLabels;//大刻度文本
 84     QVector<double> mSubTickVector;//小刻度
 85     bool mCachedMarginValid;
 86     int mCachedMargin;
 87 
 88     // introduced virtual methods:
 89     virtual int calculateMargin();
 90 
 91     // reimplemented virtual methods:
 92     virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE;//獲取缺省的反鋸齒屬性
 93     virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE;//畫坐標軸
 94     virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE;//選擇策略137 
 95     // non-virtual methods:
 96     void setupTickVectors();//計算刻度
 97     QPen getBasePen() const;//獲取基礎畫筆
 98     QPen getTickPen() const;//獲取大刻度畫筆
 99     QPen getSubTickPen() const;//獲取小刻度畫筆
100     QFont getTickLabelFont() const;//獲取刻度文本畫筆
101     QFont getLabelFont() const;//獲取坐標軸名稱文本字體
102     QColor getTickLabelColor() const;//獲取大刻度文本顏色
103     QColor getLabelColor() const;..獲取坐標軸名稱文本顏色
104 };

     具體的繪制類其實是QCPAxisPainterPrivate類,這是一個私有類,從名字就可以看出,他是一個QCPAxis類的繪制私有類,事實確實如此。刻度計算類是QCPAxisTicker,這是一個刻度計算基類,也是QCPAxis默認使用的刻度計算類,當然了這個類還有一大堆子類,都是專門用於生成指定類型的坐標軸。

2、QCPAxisTicker:刻度計算類,該類完成了大刻度、小刻度和大刻度文本的計算,供QCPAxis來調用繪制,其中generate方法是一個公有的虛方法,既可以被重寫,又可以被外部調用,QCPAxis坐標軸就是調用該接口來重新計算刻度。

 1 class QCP_LIB_DECL QCPAxisTicker
 2 {
 3     Q_GADGET
 4 public:
 5     enum TickStepStrategy//刻度生成策略
 6     {
 7         tssReadability    ///< A nicely readable tick step is prioritized over matching the requested number of ticks (see \ref setTickCount)
 8         , tssMeetTickCount ///< Less readable tick steps are allowed which in turn facilitates getting closer to the requested tick count
 9     };
10 
11     QCPAxisTicker();
12     virtual ~QCPAxisTicker();
13 
14     // setters:
15     void setTickStepStrategy(TickStepStrategy strategy);//設置刻度生成策略
16     void setTickCount(int count);//設置大刻度個數 有可能計算出來的刻度數不完全等於設置的刻度個數,取決於刻度生成策略
17     void setTickOrigin(double origin);//設置坐標軸領刻度
18 
19     // introduced virtual methods:
20     virtual void generate(const QCPRange &range, const QLocale &locale, QChar formatChar, int precision, QVector<double> &ticks, QVector<double> *subTicks, QVector<QString> *tickLabels);
21 
22 protected:
23     // introduced virtual methods:
24     virtual double getTickStep(const QCPRange &range);//根據坐標軸范圍計算步長
25     virtual int getSubTickCount(double tickStep);//根據步長計算自刻度個數
26     virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision);//根據指定語言、文本格式和精度獲取文本
27     virtual QVector<double> createTickVector(double tickStep, const QCPRange &range);//生成大刻度
28     virtual QVector<double> createSubTickVector(int subTickCount, const QVector<double> &ticks);//生成小刻度
29     virtual QVector<QString> createLabelVector(const QVector<double> &ticks, const QLocale &locale, QChar formatChar, int precision);//生成刻度文本
30 
31     // non-virtual methods:
32     void trimTicks(const QCPRange &range, QVector<double> &ticks, bool keepOneOutlier) const;//去除無效的刻度值
33     double pickClosest(double target, const QVector<double> &candidates) const;//該函數返回范圍內第一個不小於(大於或等於)指定target的值。
34 };

四、網格線

    QCPGrid網格線,這個算是和QCPAxis坐標軸類似的實現,和其他模塊關系基本都不是很大,直接繼承自QCPLayerable,頭文件格式如下,同樣的,我刪除了其中無需注釋的一部分代碼。

    在QCustomPlot的源碼設計中,一個QCPAxis坐標軸對於一個QCPGrid,這同我之前理解的圖表繪制有些不大一樣,呵呵呵。。。但是QCustomPlot就是這么干了,如果想對網格線做一些控制,有時候從QCPAxis就可以做到,因為他們直接的數據在使用上還是比較依賴。

 1 class QCP_LIB_DECL QCPGrid :public QCPLayerable
 2 {
 3     QCPGrid(QCPAxis *parentAxis);
 4 
 5     // setters:
 6     void setSubGridVisible(bool visible);//設置是否顯示自網格線
 7     void setAntialiasedSubGrid(bool enabled);//設置子網格線是否反鋸齒
 8     void setAntialiasedZeroLine(bool enabled);//設置零線(就是刻度值為0的線)是否反鋸齒
 9     void setPen(const QPen &pen);//設置畫筆
10     void setSubGridPen(const QPen &pen);//設置子網格畫筆
11     void setZeroLinePen(const QPen &pen);//設置零線畫筆
12 
13 protected:
14     bool mSubGridVisible;//子網格是否顯示標記
15     bool mAntialiasedSubGrid, mAntialiasedZeroLine;//子網格和零線是否反鋸齒標記
16     QPen mPen, mSubGridPen, mZeroLinePen;//這個就不用說了
17     QCPAxis *mParentAxis;//對於的坐標軸,一個網格線對應一個坐標軸
18     virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const;//獲取缺省的反鋸齒屬性
19     virtual void draw(QCPPainter *painter);//繪制網格線,內部調用drawGridLines和drawSubGridLines
20 
21     // non-virtual methods: 
22     void drawGridLines(QCPPainter *painter) const;//繪制網格線
23     void drawSubGridLines(QCPPainter *painter) const;//繪制子網格線
24 };

    一般來說,網格線不需要重寫,頂多就是設置一個顏色,控制是否顯示,網格線的疏密成都市和坐標軸刻度計算有關系的,因此關於網格線的計算我們就不要考慮了,下面我提供一個我自定義的刻度固定像素計算類示例

五、簡單的示例

    首先來看下效果,如圖1所示,當圖表放大時,y軸上的刻度間距是保持固定像素的。

圖1 y軸固定像素伸縮

    如下是刻度計算類頭文件,這個類實現起來還是比較簡單的,根據屏幕像素返回步長,每次步長都是按當前像素比例下計算的。

 1 class AxisFixedPixelTicker : public QCPAxisTicker
 2 {
 3 public:
 4     AxisFixedPixelTicker(QCPAxis * axis);
 5     ~AxisFixedPixelTicker();
 6 
 7 public:
 8     void SetTickPixelStep(int pixel);//設置固定像素
 9     int GetTickPixelStep() const;//獲取固定像素大小
10 
11 protected:
12     //QCPAxisTicker
13     virtual double getTickStep(const QCPRange & range) override;//重寫父類方法,根據固定像素返回步長值
14 
15 private:
16     QScopedPointer<AxisFixedPixelTickerPrivate> d_ptr;
17 };

    下面是重寫的父類接口getTickStep方法實現

 1 double AxisFixedPixelTicker::getTickStep(const QCPRange & range) 
 2 {
 3     if (d_ptr->m_pDependAxis)
 4     {
 5         bool vertical;
 6         if (d_ptr->m_pDependAxis->axisType() == QCPAxis::atLeft
 7             || d_ptr->m_pDependAxis->axisType() == QCPAxis::atRight)
 8         {
 9             vertical = true;
10         }
11         else
12         {
13             vertical = false;
14         }
15 
16         int screenLength = vertical ? d_ptr->m_pDependAxis->axisRect()->rect().height() : d_ptr->m_pDependAxis->axisRect()->rect().width();
17         return d_ptr->m_iPixel * range.size() / screenLength;
18     }
19     else
20     {
21         return __super::getTickStep(range);
22     }
23 }

六、相關文章

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

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

  QCustomplot使用分享(三) 圖

  QCustomplot使用分享(四) QCPAbstractItem

  QCustomplot使用分享(五) 布局

 

 

如果您覺得文章不錯,不妨給個 打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM