qcustomplot使用分享坐标轴和网格线

朝十晚八 朝十晚八     2022-08-13     597

关键词:

一、概述

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

qt_qcustomplot学习(代码片段)

QCustomPlot学习QCustomPlot默认提供了6个层,如下代码所示,分别是:背景层、网格层、主层、坐标轴层、图例层和矩形选择区域层。1.在一张视图中表现两个线#include"widget.h"#include"ui_widget.h"Widget::Widget(QWidget*pa... 查看详情

qt_qcustomplot学习(代码片段)

QCustomPlot学习QCustomPlot默认提供了6个层,如下代码所示,分别是:背景层、网格层、主层、坐标轴层、图例层和矩形选择区域层。1.在一张视图中表现两个线#include"widget.h"#include"ui_widget.h"Widget::Widget(QWidget*pa... 查看详情

qcustomplot(三):图形绘制基础之样式修改

参考技术A图形的外观由许多因素决定,所有这些因素都可以修改。以下是最重要的:轴的外观可以通过改变它们所用的笔和它们的标签使用的字体来修改。具体可以查看QCPAxis的文档。以下是最重要属性的快速摘要:setBasePen,setTi... 查看详情

qcustomplot学习使用分享

同时发布在http://blog.csdn.net/laixuepu/article/details/78825257QCustomplot学习使用分享QCustomplot网上和例子都是在资源和头文件中加入qcustomplot.h和qcustomplot.cpp,然后在.ui中添加Widget,然后提升为QCustomplot,然后重新命名,在mainwindow中调用,... 查看详情

qcustomplot使用分享层(完结)

...总是想把1.3.2版本拿出来比较一下,这篇文章也不例外。QCustomPlot2.0.0beta版本比1.3.2release版本有一个很大的改进那就是分层绘制,所谓分层绘制就是把一张图分几张图来绘制,最后在把这分开的几张图统一绘制到一张图上,比如... 查看详情

qcustomplot实时图形怎么让图不走了

参考技术A使用QCustomPlot绘图的基础首先你用QCustomPlot::addGraph创建一个曲线图然后你给曲线图赋一些数据点(一对QVector<double>为x,y的值)并且定义曲线图的外观(线型,分散图案,颜色,线笔)子厚调用QCustomPlot::replot。注意replot应该被... 查看详情

如何在 QCustomPlot 中隐藏网格并仅显示零线?

】如何在QCustomPlot中隐藏网格并仅显示零线?【英文标题】:HowtohidegridandshowonlyzerolineinQCustomPlot?【发布时间】:2014-01-1306:58:40【问题描述】:隐藏网格时有什么方法可以在QCustomPlot中显示零线?我尝试使用以下行隐藏网格:ui->... 查看详情

在excel图表中怎么设置网格线之间的距离啊 ?

参考技术AExcel中分别为两个坐标轴都提供了主要、次要网格线选项,对于不同版本,添加网格线方法为:1、Excel:选中图表→图表菜单→图表选项→网格线2、Excel2007及以上:选中图表→图表工具→布局→网格线 查看详情

qcustomplot坐标轴绘图按x轴大小排序方式绘图

使用qcustomplot1.0绘制二维坐标轴,ui->widget->graph(0)->addData发现并不是按输入点的先后顺序连线,而是按坐标轴的大小排序绘的图。请问该怎么设置才能使它按点输入的先后顺序绘图?MouseEvent->pos()可以获得相对于viewport()... 查看详情

[wpf]在canvas上绘制网格线

...lyline就可以基本的轨迹功能。为使轨迹不过于单调增加了网格线背景。学习WPF:第6个月。网格线的绘制主要依赖窗口的宽高和设定的间隔计算,画多少行,画多少列,画多长,画多高。支持窗口缩放只要是监听SizeChanged的回调事... 查看详情

qcustomplot之层和布局(四)

参考技术A在QCustomPlot中,一切可显示的对象都是继承自层元素QCPLayerable,层QCPLayer则管理着层元素,QCustomPlot利用层决定了不同元素的绘制顺序层有两种刷新模式:默认只有overlay层启用了lmBuffered单独绘制机制,其它层都共享一个... 查看详情

怎么给qcustomplot坐标轴添加单位

效果图:添加voidsetAxisFormat(QStringformat);添加函数setAxisFormat(QStringformat);修改draw函数添加变量m_formatCSDN社区图书馆,开张营业!深读计划,写书评领图书福利~ 查看详情

在 Rails 中使用 ChartKick 添加网格线

】在Rails中使用ChartKick添加网格线【英文标题】:AddGridlinesusingChartKickinRails【发布时间】:2021-12-1422:58:37【问题描述】:使用ChartKick和chart.js我想添加水平网格线。数据范围是100到200..我希望每10个单位有一个水平网格线。<script... 查看详情

id基本操作(标尺,参考线,网格)5.11

参考线:标尺参考线,分栏参考线,出血参考线。在创建参考线之前确保标尺和参考线都可见。并且选中正确的跨页和页面作为目标,“版面”“创建参考线”可以输入数值创建参考线。跨页参考线的创建:拖动参考线时鼠标必... 查看详情

哪些网格数据格式分别提供位置、法线和 UV 坐标的索引?

...【发布时间】:2017-04-2708:56:09【问题描述】:我的游戏将使用大量带有硬边的低多边形网格。这意味着很多时候,一个顶点位置将使用多个法线和UV坐标。因此,将顶点位置、法线和UV拆分为3个单独的数组,然后每个 查看详情

怎样在matlab图形中添加网格?

...果想要添加网格线的数据,及添加更密集的网格线,可以使用gridminor这个指令。4、对于使用plotyy进行双y轴作图的函数来说,gridon或者gridminor只能添加横坐标网格线。5、对于在MATLAB图形显示窗口工具——查看布局网格,指的是在... 查看详情

百度裁减网格纸

...一些点过的点,每个点都在网格点上,若把网格看成一个坐标轴平行于网格线的坐标系的话,每个点可以用一对整数x,y来表示。度度熊必须沿着网格线画一个正方形,使所有点在正方形的内部或者边界。然后把这个正方形剪下... 查看详情

flex 图表网格线虚线

...gridlinesdotted【发布时间】:2010-12-2021:48:39【问题描述】:使用Flex的LineChart组件:如何使水平网格线(图表内的背景)点缀?使用mx:horizo​​ntalStroke中的mx:Stroke,我只能设置重量、颜色和alpha等属性。我想把线画成虚线...这就是... 查看详情