1、QCPAxis,如下是QCPAxis的头文件,我从中删除了大量不需要注释的部分,但是很是剩下许多,为了写注释方便所以我没有把代码折叠,有兴趣的同学可以阅读下其中的中文注释,其实这个类仅仅是用来连接计算和绘制坐标轴的一个类,也可以说是暴露给使用者的一个导出类。

1 class QCP_LIB_DECL QCPAxis : public QCPLayerable
2 {
3 enum AxisType {//坐标轴类型,在一个坐标轴矩形QCPAxisRect中包含左、上、右和下四条坐标轴
4 atLeft = 0x01 ///< 0x01 Axis is vertical and on the left side of the axis rect
5 , atRight = 0x02 ///< 0x02 Axis is vertical and on the right side of the axis rect
6 , atTop = 0x04 ///< 0x04 Axis is horizontal and on the top side of the axis rect
7 , atBottom = 0x08 ///< 0x08 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 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 mTicker;//坐标轴刻度计算类
82 QVector mTickVector;//大刻度
83 QVector mTickVectorLabels;//大刻度文本
84 QVector 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 &ticks, QVector *subTicks, QVector *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 createTickVector(double tickStep, const QCPRange &range);//生成大刻度
28 virtual QVector createSubTickVector(int subTickCount, const QVector &ticks);//生成小刻度
29 virtual QVector createLabelVector(const QVector &ticks, const QLocale &locale, QChar formatChar, int precision);//生成刻度文本
30
31 // non-virtual methods:
32 void trimTicks(const QCPRange &range, QVector &ticks, bool keepOneOutlier) const;//去除无效的刻度值
33 double pickClosest(double target, const QVector &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 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 }