zoukankan      html  css  js  c++  java
  • 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 
    ef setTicker to a 
    ef 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 
    ef 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. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。 

  • 相关阅读:
    366. Find Leaves of Binary Tree输出层数相同的叶子节点
    716. Max Stack实现一个最大stack
    515. Find Largest Value in Each Tree Row查找一行中的最大值
    364. Nested List Weight Sum II 大小反向的括号加权求和
    156. Binary Tree Upside Down反转二叉树
    698. Partition to K Equal Sum Subsets 数组分成和相同的k组
    244. Shortest Word Distance II 实现数组中的最短距离单词
    187. Repeated DNA Sequences重复的DNA子串序列
    java之hibernate之基于主键的双向一对一关联映射
    java之hibernate之基于主键的单向一对一关联映射
  • 原文地址:https://www.cnblogs.com/swarmbees/p/6059812.html
Copyright © 2011-2022 走看看