文章首发自公众号:: nullobject 。个人站点:https://www.nullobject.cn这篇文章主要介绍QXYSeries类的API及其使用0x00 前言QXYSeries作为QAbstractSeries的派生类之一,主要负责实现以二维点集为数据源,坐标类型为二维坐标系的图表类型,包括折线图、曲线图和散点图等。QXYSeries封装了大量对数据源进行增删改操作的函数和信号,同时内部实现了控制数据点在坐标系上的显示形态(点标签的格式、颜色、是否显示等)的功能。0x01 显示和控制点标签Qt图表中的点标签指的是数据点在图表上对应位置的附加信息显示(比如点的坐标或者其他信息):QXYSeries类中提供了pointLabels*开头的五个属性及对应的方法和信号来操作点标签的显示风格。pointLabelsClipping : 获取和设置是否对点标签超出绘图区域边缘的部分进行裁剪:bool pointLabelsClipping() const;void setPointLabelsClipping(bool enabled = true);效果:可以看到,当设置pointLabelsClipping属性为true(默认值)时,点标签超出绘图区域的部分会被裁剪掉。pointLabelsClipping属性发生改变时,会触发pointLabelsClippingChanged(bool clipping)信号。pointLabelsColor : 获取和设置点标签的显示颜色:QColor pointLabelsColor() const;void setPointLabelsColor(const QColor &color);效果:上图分别为将pointLabelsColor属性设置为黑色和绿色的效果。看到这您有可能会有疑问:咦怎么只改变了坐标的颜色,而折线上点的颜色没有变?注意了,这里的点标签是指图表上对数据点加以说明的信息部分,不包括点本身的显示。pointLabelsColor属性发生改变时,会触发pointLabelsColorChanged(const QColor &color)信号。pointLabelsFont : 获取和设置点标签的显示字体:QFont pointLabelsFont() const;void setPointLabelsFont(const QFont &font);该属性通过一个QFont设置来实现:// 获取pointLabels默认字体QFont font = series->pointLabelsFont();// 加粗font.setBold(true);// 斜体font.setItalic(true);// 设置字体大小font.setPointSize(12);// 设置字体为Arial类型font.setFamily(QStringLiteral(“Arial”));// 更新pointLabels字体series->setPointLabelsFont(font);效果:pointLabelsFont属性发生改变时,会触发pointLabelsFontChanged(const QFont &font)信号。pointLabelsFormat : 获取和设置点标签的显示格式:QString pointLabelsFormat() const;void setPointLabelsFormat(const QString &format);QXYSeries类提供了两个占位符来设置点标签显示真实坐标数据:@xPointX轴坐标@yPointY轴坐标例如,我们需要以:(15,23)这样的格式来显示点标签,可以这样设置,即可实现上文中点标签的显示格式效果:// 设置点标签格式series->setPointLabelsFormat(QStringLiteral("(@xPoint,@yPoint)"));pointLabelFormat属性默认被设置为没有括号的坐标格式:@xPoint, @yPoint。pointLabelsFormat属性发生改变时,会触发pointLabelsFormatChanged(const QString &format)信号。pointLabelsVisible : 获取和设置显示/隐藏点标签:bool pointLabelsVisible() const;void setPointLabelsVisible(bool visible=true);该属性默认被设置为false。// 隐藏点标签series->setPointLabelsVisible(false);效果:pointLabelsVisible属性发生改变时,会触发pointLabelsVisibilityChanged(bool visible)信号。pointsVisible : 获取和设置显示/隐藏点在图表上的标注:bool pointsVisible() const;void setPointsVisible(bool visible=true);与pointsLabelVisible不同,pointsLabelVisible设置的是点标签的显示,而pointsVisible设置的是点本身在图表上的位置标注。该属性默认被设置为false。对比显示和隐藏点标注效果:0x02 对数据源进行增删改QXYSeries类中封装了一系列的重载方法用于操作图表的数据源进行增删改。QXYSeries内部用一个模板类型为QPointF的QVector来持有数据源,其声明在qxyseries_p.h头文件内:增加数据可以调用append的对应重载方法,或者是重载操作符<<添加单个点或者整个点集到数据源的尾部:void append(qreal x, qreal y);void append(const QPointF &point);void append(const QList<QPointF> &points);QXYSeries& operator<<(const QPointF &point);QXYSeries& operator<<(const QList<QPointF> &points);也可以调用insert方法将数据点插入到数据源的指定位置:void insert(int index, const QPointF &point);对应地,不管以何种方式,成功添加数据后都会触发pointAdded(int index)信号,index为被添加的数据的下标。需要注意:每添加一个点就会触发一次pointAdded信号,即批量添加数据时会触发对应次数的pointAdded。删除数据QXYSeries提供了remove重载方法和removePoints方法来移除目标数据:// 删除指定坐标的点void remove(qreal x, qreal y);void remove(const QPointF &point);// 删除指定索引下标的点void remove(int index);// 从下标index位置开始,删除count数量的点void removePoints(int index, int count);与增加数据类似,成功删除数据后会触发对应次数的pointRemoved(int index)信号,index为被删除的数据的下标。修改数据源修改数据源通过replace系列的重载方法实现:// 替换具体坐标的点void replace(qreal oldX, qreal oldY, qreal newX, qreal newY);void replace(const QPointF &oldPoint, const QPointF &newPoint);// 替换指定索引下标的点void replace(int index, qreal newX, qreal newY);void replace(int index, const QPointF &newPoint);// 替换整个数据源void replace(QList<QPointF> points);void replace(QVector<QPointF> points);当只替换数据源的局部数据点(调用前四种重载方法)时,会触发pointReplaced(int index)信号,index为被替换的点的下标;而当替换了整个数据源数据(调用后两种方法)时,则会触发pointsReplaced()信号。需要注意:调用replace后两种重载替换整个数据源时,传QList还是传QVector在性能上是有所区别的:直接传入QList结构的数据集远远比逐个点替换或者先清除所有点再添加这两种方式的效率要高。而直接传入QVector结构的数据集又比前者效率要高。因此:需要批量更新数据点时,应当优先选择void replace(QVector<QPointF> points);这个重载方法。究其原因:本小节一开始就介绍了,QXYSeries内部持有数据源的数据结构为QVector<QPointF>,而参数为QList<QPointF>的重载方法的内部实现也是将QList转换为QVector,再调用参数为QVector<QPointF> 的重载方法实现对数据的更新,无形中多了一个数据转换的步骤,拉低性能:Tips:QList和QVector两个容器本身的效率上也是有区别的,Qt官方推荐优先使用QVector。详细可以参考QVector的官方文档介绍。获取数据源QXYseries提供了返回类型分别为QList<QPointF>和QVector<QPointF>的方法获取数据源:QList<QPointF> points() const;QVector<QPointF> pointsVector() const;与更新replace方法批量更新数据源的重载类似,points()方法获取数据源的方法,内部实现也是获取原始数据源再将其转为QList类型返回;pointsVector()方法则直接返回原始的QVector数据源。0x03 QXYSeries中的鼠标操作QXYSeries共提供了五个鼠标事件响应信号,分别是:单击clicked、双击doubleClicked、鼠标键按下pressed,鼠标键松开released、光标移到图表线上或从图表移开hovered:series->connect(series,&QLineSeries::clicked,[](const QPointF& point){ qDebug() << “point clicked:” << point;});series->connect(series,&QLineSeries::doubleClicked,[](const QPointF& point){ qDebug() << “point double clicked:” << point;});series->connect(series,&QLineSeries::hovered,[](const QPointF& point,bool state){ qDebug() << “point hovered:” << point << " state:" << (state?“光标移动到图表上”:“光标从图表上移开”);});series->connect(series,&QLineSeries::pressed,[](const QPointF& point){ qDebug() << “point pressed:” << point;});series->connect(series,&QLineSeries::released,[](const QPointF& point){ qDebug() << “point released:” << point;});运行程序,执行光标移动到图表序列上->左键双击->光标从图表序列上方移开,结果如下:point hovered: QPointF(4.58291,8.71473) state: moved to seriespoint pressed: QPointF(4.58291,8.71473)point released: QPointF(4.58291,8.71473)point clicked: QPointF(4.58291,8.71473)point double clicked: QPointF(4.58291,8.71473)point pressed: QPointF(4.58291,8.71473)point released: QPointF(4.58291,8.71473)point clicked: QPointF(4.58291,8.71473)point hovered: QPointF(4.71022,8.18182) state: moved from series0x04 The End.