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

class QCP_LIB_DECL QCPAxis : public QCPLayerable
{
    enum AxisType {//坐标轴类型,在一个坐标轴矩形QCPAxisRect中包含左、上、右和下四条坐标轴
        atLeft = 0x01  ///< <tt>0x01</tt> Axis is vertical and on the left side of the axis rect
        , atRight = 0x02  ///< <tt>0x02</tt> Axis is vertical and on the right side of the axis rect
        , atTop = 0x04  ///< <tt>0x04</tt> Axis is horizontal and on the top side of the axis rect
        , atBottom = 0x08  ///< <tt>0x08</tt> Axis is horizontal and on the bottom side of the axis rect
    };
    enum LabelSide {//坐标轴刻度上的文本的位置,刻度线里or外
        lsInside    ///< Tick labels will be displayed inside the axis rect and clipped to the inner axis rect
        , lsOutside  ///< Tick labels will be displayed outside the axis rect
    };
    enum ScaleType {//坐标轴类型,直线or对数线
        stLinear       ///< Linear scaling
        , stLogarithmic ///< Logarithmic scaling with correspondingly transformed axis coordinates (possibly also \ref setTicker to a \ref QCPAxisTickerLog instance).
    };
    enum SelectablePart {/坐标轴可以被选中的部分
        spNone = 0      ///< None of the selectable parts
        , spAxis = 0x001  ///< The axis backbone and tick marks
        , spTickLabels = 0x002  ///< Tick labels (numbers) of this axis (as a whole, not individually)
        , spAxisLabel = 0x004  ///< The axis label
    };

    explicit QCPAxis(QCPAxisRect *parent, AxisType type);
    virtual ~QCPAxis();
  //所有的get接口已经被我删除  看到对应的set接口,get接口的含义就不言而喻
    // setters:
    Q_SLOT void setScaleType(QCPAxis::ScaleType type);//设置坐标轴类型  直线or对数
    Q_SLOT void setRange(const QCPRange &range);//设置坐标轴范围
    void setRange(double lower, double upper); 33     void setTicker(QSharedPointer<QCPAxisTicker> ticker);//设置坐标轴计算刻度类,该参数是一个shared型智能指针,因此可以被多个坐标轴来同时使用
    void setTicks(bool show);//是否显示坐标轴,如果不显示坐标轴,那么网格线也就没有啦,因为没有了坐标轴刻度
    void setTickLabels(bool show);//是否显示坐标轴文本
    void setTickLabelPadding(int padding);//设置坐标走文本距离坐标轴线距离
    void setTickLabelFont(const QFont &font);//设置文本字体
    void setTickLabelColor(const QColor &color);//设置文本颜色
    void setTickLabelRotation(double degrees);//设置文本角度
    void setTickLabelSide(LabelSide side);//设置文本在刻度线里or外
    void setNumberFormat(const QString &formatCode);//设置文本格式
    void setNumberPrecision(int precision);//设置文本精度
    void setTickLength(int inside, int outside = 0);//设置大刻度高度
    void setTickLengthIn(int inside);//设置大刻度在里边长度
    void setTickLengthOut(int outside);//设置大刻度在外边长度
    void setSubTicks(bool show);//设置是否显示小刻度
    void setSubTickLength(int inside, int outside = 0);//设置小刻度高度
    void setSubTickLengthIn(int inside);//设置小刻度在坐标轴线里边长度
    void setSubTickLengthOut(int outside);//设置小刻度在坐标轴线外边长度
    void setBasePen(const QPen &pen);//设置基础线画笔  基础线是零线,即可以认为是坐标轴刻度为0的线
    void setTickPen(const QPen &pen);//设置大刻度画笔
    void setSubTickPen(const QPen &pen);//设置小刻度画笔
    void setLabelFont(const QFont &font);//设置坐标轴名称字体画笔
    void setLabelColor(const QColor &color);//设置坐标轴名称字体颜色
    void setLabel(const QString &str);//设置坐标轴名称文本
    void setLabelPadding(int padding);//设置坐标轴名称文本距离坐标轴刻度线距离
    void setPadding(int padding);//设置坐标轴距离边界距离
    void setOffset(int offset);//设置偏移量
    void setSelectedTickLabelFont(const QFont &font);//设置选中刻度文本时字体
    void setSelectedLabelFont(const QFont &font);//设置选中坐标轴名称时字体
    void setSelectedTickLabelColor(const QColor &color);//选中刻度文本时颜色
    void setSelectedLabelColor(const QColor &color);//选中坐标轴名称时颜色
    void setSelectedBasePen(const QPen &pen);//选中基础线时画笔
    void setSelectedTickPen(const QPen &pen);//选中大刻度时画笔
    void setSelectedSubTickPen(const QPen &pen);//选中小刻度时画笔
    Q_SLOT void setSelectableParts(const QCPAxis::SelectableParts &selectableParts);//设置能选中项的类型
    Q_SLOT void setSelectedParts(const QCPAxis::SelectableParts &selectedParts);
    void setLowerEnding(const QCPLineEnding &ending);//设置坐标轴小刻度端样式
    void setUpperEnding(const QCPLineEnding &ending);//坐标轴大刻度端样式 73
    // non-property methods:
    Qt::Orientation orientation() const { return mOrientation; }//坐标轴朝向
    int pixelOrientation() const { return rangeReversed() != (orientation() == Qt::Vertical) ? -1 : 1; }
    void moveRange(double diff);//移动坐标轴
    void scaleRange(double factor);//按比例因子缩放
    void scaleRange(double factor, double center);//按范围缩放 81     void rescale(bool onlyVisiblePlottables = false);//重新适配坐标轴范围
    double pixelToCoord(double value) const;//像素到坐标轴坐标系
    double coordToPixel(double value) const;//坐标轴坐标系到像素 85     QList<QCPAbstractPlottable*> plottables() const;//所有的图
    QList<QCPGraph*> graphs() const;//所有的折线
    QList<QCPAbstractItem*> items() const;//所有的示意项 92
protected:
    AxisType mAxisType;//坐标轴类型
    QCPAxisRect *mAxisRect;//坐标轴所在矩形116
    // non-property members:
    QCPGrid *mGrid;//网格120     QSharedPointer<QCPAxisTicker> mTicker;//坐标轴刻度计算类
    QVector<double> mTickVector;//大刻度
    QVector<QString> mTickVectorLabels;//大刻度文本
    QVector<double> mSubTickVector;//小刻度
    bool mCachedMarginValid;
    int mCachedMargin;

    // introduced virtual methods:
    virtual int calculateMargin();

    // reimplemented virtual methods:
    virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE;//获取缺省的反锯齿属性
    virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE;//画坐标轴
    virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE;//选择策略137
    // non-virtual methods:
    void setupTickVectors();//计算刻度
    QPen getBasePen() const;//获取基础画笔
    QPen getTickPen() const;//获取大刻度画笔
    QPen getSubTickPen() const;//获取小刻度画笔
    QFont getTickLabelFont() const;//获取刻度文本画笔
    QFont getLabelFont() const;//获取坐标轴名称文本字体
    QColor getTickLabelColor() const;//获取大刻度文本颜色
    QColor getLabelColor() const;..获取坐标轴名称文本颜色
};

     具体的绘制类其实是QCPAxisPainterPrivate类,这是一个私有类,从名字就可以看出,他是一个QCPAxis类的绘制私有类,事实确实如此。刻度计算类是QCPAxisTicker,这是一个刻度计算基类,也是QCPAxis默认使用的刻度计算类,当然了这个类还有一大堆子类,都是专门用于生成指定类型的坐标轴。

2、QCPAxisTicker:刻度计算类,该类完成了大刻度、小刻度和大刻度文本的计算,供QCPAxis来调用绘制,其中generate方法是一个公有的虚方法,既可以被重写,又可以被外部调用,QCPAxis坐标轴就是调用该接口来重新计算刻度。

class QCP_LIB_DECL QCPAxisTicker
{
    Q_GADGET
public:
    enum TickStepStrategy//刻度生成策略
    {
        tssReadability    ///< A nicely readable tick step is prioritized over matching the requested number of ticks (see \ref setTickCount)
        , tssMeetTickCount ///< Less readable tick steps are allowed which in turn facilitates getting closer to the requested tick count
    };

    QCPAxisTicker();
    virtual ~QCPAxisTicker();

    // setters:
    void setTickStepStrategy(TickStepStrategy strategy);//设置刻度生成策略
    void setTickCount(int count);//设置大刻度个数 有可能计算出来的刻度数不完全等于设置的刻度个数,取决于刻度生成策略
    void setTickOrigin(double origin);//设置坐标轴领刻度

    // introduced virtual methods:
    virtual void generate(const QCPRange &range, const QLocale &locale, QChar formatChar, int precision, QVector<double> &ticks, QVector<double> *subTicks, QVector<QString> *tickLabels);

protected:
    // introduced virtual methods:
    virtual double getTickStep(const QCPRange &range);//根据坐标轴范围计算步长
    virtual int getSubTickCount(double tickStep);//根据步长计算自刻度个数
    virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision);//根据指定语言、文本格式和精度获取文本
    virtual QVector<double> createTickVector(double tickStep, const QCPRange &range);//生成大刻度
    virtual QVector<double> createSubTickVector(int subTickCount, const QVector<double> &ticks);//生成小刻度
    virtual QVector<QString> createLabelVector(const QVector<double> &ticks, const QLocale &locale, QChar formatChar, int precision);//生成刻度文本

    // non-virtual methods:
    void trimTicks(const QCPRange &range, QVector<double> &ticks, bool keepOneOutlier) const;//去除无效的刻度值
    double pickClosest(double target, const QVector<double> &candidates) const;//该函数返回范围内第一个不小于(大于或等于)指定target的值。
};

四、网格线

    QCPGrid网格线,这个算是和QCPAxis坐标轴类似的实现,和其他模块关系基本都不是很大,直接继承自QCPLayerable,头文件格式如下,同样的,我删除了其中无需注释的一部分代码。

    在QCustomPlot的源码设计中,一个QCPAxis坐标轴对于一个QCPGrid,这同我之前理解的图表绘制有些不大一样,呵呵呵。。。但是QCustomPlot就是这么干了,如果想对网格线做一些控制,有时候从QCPAxis就可以做到,因为他们直接的数据在使用上还是比较依赖。

class QCP_LIB_DECL QCPGrid :public QCPLayerable
{
    QCPGrid(QCPAxis *parentAxis);

    // setters:
    void setSubGridVisible(bool visible);//设置是否显示自网格线
    void setAntialiasedSubGrid(bool enabled);//设置子网格线是否反锯齿
    void setAntialiasedZeroLine(bool enabled);//设置零线(就是刻度值为0的线)是否反锯齿
    void setPen(const QPen &pen);//设置画笔
    void setSubGridPen(const QPen &pen);//设置子网格画笔
    void setZeroLinePen(const QPen &pen);//设置零线画笔

protected:
    bool mSubGridVisible;//子网格是否显示标记
    bool mAntialiasedSubGrid, mAntialiasedZeroLine;//子网格和零线是否反锯齿标记
    QPen mPen, mSubGridPen, mZeroLinePen;//这个就不用说了
    QCPAxis *mParentAxis;//对于的坐标轴,一个网格线对应一个坐标轴
    virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const;//获取缺省的反锯齿属性
    virtual void draw(QCPPainter *painter);//绘制网格线,内部调用drawGridLines和drawSubGridLines

    // non-virtual methods:
    void drawGridLines(QCPPainter *painter) const;//绘制网格线
    void drawSubGridLines(QCPPainter *painter) const;//绘制子网格线
};

    一般来说,网格线不需要重写,顶多就是设置一个颜色,控制是否显示,网格线的疏密成都市和坐标轴刻度计算有关系的,因此关于网格线的计算我们就不要考虑了,下面我提供一个我自定义的刻度固定像素计算类示例

五、简单的示例

    首先来看下效果,如图1所示,当图表放大时,y轴上的刻度间距是保持固定像素的。

图1 y轴固定像素伸缩

    如下是刻度计算类头文件,这个类实现起来还是比较简单的,根据屏幕像素返回步长,每次步长都是按当前像素比例下计算的。

class AxisFixedPixelTicker : public QCPAxisTicker
{
public:
    AxisFixedPixelTicker(QCPAxis * axis);
    ~AxisFixedPixelTicker();

public:
    void SetTickPixelStep(int pixel);//设置固定像素
    int GetTickPixelStep() const;//获取固定像素大小

protected:
    //QCPAxisTicker
    virtual double getTickStep(const QCPRange & range) override;//重写父类方法,根据固定像素返回步长值

private:
    QScopedPointer<AxisFixedPixelTickerPrivate> d_ptr;
};

    下面是重写的父类接口getTickStep方法实现

double AxisFixedPixelTicker::getTickStep(const QCPRange & range)
{
    if (d_ptr->m_pDependAxis)
    {
        bool vertical;
        if (d_ptr->m_pDependAxis->axisType() == QCPAxis::atLeft
            || d_ptr->m_pDependAxis->axisType() == QCPAxis::atRight)
        {
            vertical = true;
        }
        else
        {
            vertical = false;
        }

        int screenLength = vertical ? d_ptr->m_pDependAxis->axisRect()->rect().height() : d_ptr->m_pDependAxis->axisRect()->rect().width();
        return d_ptr->m_iPixel * range.size() / screenLength;
    }
    else
    {
        return __super::getTickStep(range);
    }
}

 

  • 0
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QCustomPlot是一个功能强大的Qt绘库,可以用于绘制各种表,包括极坐标。 要绘制极坐标,首先需要设置表的坐标系为极坐标。可以通过以下代码实现: ```cpp QCustomPlot customPlot; // 创建一个 QCustomPlot 对象 // 设置坐标轴类型为极坐标 customPlot->setPolar(true); // 设置极坐标网格线的样式 customPlot->xAxis->grid()->setLineStyle(QCPAxisGrid::lsCircular); // 设置径向网格线样式 customPlot->yAxis->grid()->setSubGridVisible(true); // 设置角向网格线可见 customPlot->yAxis->grid()->setSubGridLineStyle(QCPAxisGrid::lsLine); // 设置角向子网格线样式 ``` 然后,可以使用QCPGraph类在极坐标上绘制数据。绘制极坐标的步骤与绘制普通二维表类似,需要先创建一个表对象,然后设置数据和样式。以下是一个示例代码,实现在极坐标上绘制一个正弦函数曲线: ```cpp // 创建一个 QCPGraph 对象 QCPGraph *graph = new QCPGraph(customPlot->xAxis, customPlot->yAxis); // 设置曲线的线条颜色和宽度 graph->setPen(QPen(Qt::red)); graph->setLineStyle(QCPGraph::lsLine); graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4)); // 设置曲线的数据点 QVector<double> xData, yData; int pointCount = 100; // 数据点个数 double angleStep = 2 * M_PI / (pointCount - 1); // 角度步长 for (int i = 0; i < pointCount; ++i) { double angle = i * angleStep; double value = std::sin(angle); xData.append(angle); yData.append(value); } graph->setData(xData, yData); // 更新customPlot->replot(); ``` 以上代码在极坐标上绘制一个红色的正弦函数曲线,并设置曲线的数据点为100个。 通过以上步骤,就可以使用QCustomPlot绘制极坐标表了。根据不同的需求,可以添加更多的表元素,如例、标题等,以实现更加丰富的可视化效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值