C++ Qt开发:Charts折线图绘制详解
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QCharts
折线图的常用方法及灵活运用。
折线图(Line Chart)是一种常用的数据可视化图表,用于展示随着时间、类别或其他有序变量而变化的趋势。折线图通过将数据点连接起来形成折线,直观地展示了变量之间的趋势和关系。
折线图通常用于以下环境:
- 时间序列数据: 显示随时间变化的数据趋势,例如股票价格、气温变化等。
- 比较趋势: 可以比较不同组之间的趋势,例如不同产品的销售趋势。
- 展示模式或关联关系: 用于显示变量之间的相关性或模式,例如销售额和广告投入之间的关系。
折线图的基本结构包括:
- 横轴(X轴): 通常表示时间或类别。
- 纵轴(Y轴): 表示变量的值。可以是数值,也可以是百分比或其他度量。
- 数据点: 在图表上表示具体的数据值的点。
- 折线: 将数据点连接起来的线,形成变化趋势。
在Qt中,可以使用图表库来创建折线图。通过在程序中添加相应的数据点,并设置合适的轴和样式,你可以轻松创建出漂亮且具有信息表达能力的折线图。
在之前的文章中笔者简单创建了一个折线图,由于之前的文章只是一个概述其目的是用于让读者理解绘图组件是如何被引用到项目中的,以及如何实际使用,本章我们将具体分析折线图的绘制功能,详细介绍图表各个部分的设置和操作,包括图标的标题、图例、边距等属性的设置,QLineSeries序列的属性设置,QValueAxis坐标轴的属性设置等,通过本章的学习读者可以掌握QChart
绘图的核心方法。
1.1 图表设置
1.1.1 设置标题
首先我们来实现对图表的设置,通常情况下图表中的标题可以通过setTitle
来设置,而通过setTitleFont
可以设置标题字体,通常设置字体需要使用QFont
类,以下是 QFont
类中常用的方法的说明和概述:
方法 | 描述 |
---|---|
QFont() |
默认构造函数,创建一个默认字体。 |
QFont(const QString &family, int pointSize = -1, int weight = -1, bool italic = false) |
带参数的构造函数,创建一个具有指定族、大小、粗细和斜体属性的字体。 |
QString family() const |
返回字体的族(family)。 |
void setFamily(const QString &family) |
设置字体的族。 |
int pointSize() const |
返回字体的大小(以点为单位)。 |
void setPointSize(int pointSize) |
设置字体的大小。 |
int weight() const |
返回字体的粗细。 |
void setWeight(int weight) |
设置字体的粗细。 |
bool italic() const |
返回字体是否为斜体。 |
void setItalic(bool italic) |
设置字体是否为斜体。 |
QString styleName() const |
返回字体的样式名称。 |
void setStyleName(const QString &styleName) |
设置字体的样式名称。 |
bool bold() const |
返回字体是否为粗体。 |
void setBold(bool enable) |
设置字体是否为粗体。 |
bool exactMatch() const |
检查字体是否与指定的字体精确匹配。 |
QFontMetrics metrics() const |
返回字体的度量信息,如字符高度、宽度等。 |
bool operator==(const QFont &other) const |
比较两个字体是否相等。 |
bool operator!=(const QFont &other) const |
比较两个字体是否不相等。 |
QFont &operator=(const QFont &font) |
重载赋值运算符,用于将一个字体的值赋给另一个字体。 |
这些方法允许你设置和获取字体的各种属性,如族、大小、粗细、斜体等。你可以使用这些方法来创建和调整字体,以满足应用程序的设计需求。
通过创建一个 QFont
对象 titleFont
,然后设置字体的家族、大小和粗细。最后,通过 setTitleFont
方法将这个字体应用到图表的标题上,具体实现代码如下所示;
// 设置顶部标题 |
你可以根据需要调整字体的其他属性,例如设置斜体、下划线等。调整 setFamily
、setPointSize
、setBold
等方法的参数,则用于控制这三个属性,当然如果不希望出现顶部提示则可以忽略设置setTitle
属性;
1.1.2 图表主题
图表主题的选择可以通过setTheme
属性设置,在Qt中默认支持的主题有8种可以选择,通过使用不同的属性可以设置不同的样式表或主题,以影响应用程序的外观和感觉。
- Light(亮): 一种明亮的主题或样式,通常背景颜色较浅,前景颜色较深,使得界面看起来清晰明了。
- BlueCerulean(蓝天蓝): 一个以蓝色为主调的主题,可能会给应用程序带来清新和现代的感觉。
- Dark(暗): 一种较暗的主题,背景颜色可能较深,前景颜色相应较亮。适合创建更为暗调的用户界面。
- BrownSand(棕沙): 以棕色为主的主题,可能给应用程序带来温暖和自然的感觉。
- BlueNcs(蓝NCS): 一种以蓝色为主的主题,NCS 可能指的是一种颜色标准。
- HighContrast(高对比度): 一个高对比度的主题,通常用于提供更好的可访问性,特别适用于视力受损的用户。
- BlueIcy(蓝冷): 一种以蓝色为主,可能带有冷色调的主题。
- Qt(默认): 使用 Qt 默认主题,这个主题通常会遵循操作系统的外观,保持一致性。
而同样的设置图表展示动画则可以通过setAnimationOptions
属性来设置,通常动画属性有4种选项,这些设置通常用于控制图表和轴的动画效果。以下是简要说明:
- NoAnimation(无动画):
- 不使用动画效果。图表和轴的状态变化将会立即生效,没有平滑的过渡效果。
- GridAxisAnimations(轴网格动画):
- 使用动画效果来显示或隐藏轴的网格线。在显示或隐藏轴网格时,会有一个平滑的过渡效果。
- SeriesAnimations(数据系列动画):
- 使用动画效果来显示或隐藏数据系列。当数据系列被添加或移除时,或者改变可见性时,会有平滑的过渡效果。
- AllAnimations(所有动画):
- 同时启用轴网格动画和数据系列动画。这样会在显示或隐藏轴网格和数据系列时都有平滑的过渡效果。
这些效果的设置通常需要使用下标的方式,而下标索引是从0开始的,案例中我们使用Qt
默认主题,并将动画AllAnimations
完全启用,当然读者也可以将其定义为特定字符串方便使用,如下所示;
// ------------------------------------------ |
当设置动画与主题色以后,再次打开程序此时就会展现出所有的过度动画以及默认的主题,如下图所示;
1.1.3 图例设置
图例设置,图例指的是上图中的顶部(一分钟负载、五分钟负载)的提示信息,通常是一个QLegend
类的对象,通过QChart::legend()
可以获取到图表的图例,图例是Qt组件根据数据集自动生成的,当然某些属性我们也是可以调整的,例如图例位置、颜色、字体等。
例如,设置图例在图标的上下左右四个方位,以下枚举常量代表了对齐方式,可以用于设置控件或绘图元素在其父元素中的位置。
Qt::AlignTop
(顶部对齐):- 控件或元素将与其父元素的顶部对齐。
Qt::AlignBottom
(底部对齐):- 控件或元素将与其父元素的底部对齐。
Qt::AlignLeft
(左对齐):- 控件或元素将与其父元素的左侧对齐。
Qt::AlignRight
(右对齐):- 控件或元素将与其父元素的右侧对齐。
这些对齐方式常用于设置布局、排列控件或绘图元素的位置。例如,当你使用布局管理器(如 QVBoxLayout
或 QHBoxLayout
)时,可以通过设置对齐方式来控制子控件在父控件中的相对位置,同理当使用setAlignment()
函数时就可以用于设置QChart
图表中的图例位置。
// ------------------------------------------ |
如上代码所示,由于我们最终覆盖了上下左属性,图例将会停留在最右侧,输出效果图如下;
图例的字体与颜色也可以被自定义,字体的定义与顶部标题的定义相同,通过调用QFont
来设置字体,通过QColor
则用于设置颜色,字体类我们说过了,这里就说一下QColor
中有哪些方法可以使用吧。
以下是 QColor
类中常用的方法的说明和概述:
方法 | 描述 |
---|---|
QColor() |
默认构造函数,创建一个无效的颜色对象。 |
QColor(int r, int g, int b, int a = 255) |
构造函数,使用RGB值和可选的透明度(Alpha通道)创建颜色对象。 |
QColor(Qt::GlobalColor color) |
构造函数,使用Qt全局颜色枚举值创建颜色对象。 |
QColor(const QString &name) |
构造函数,使用颜色名创建颜色对象。例如,”red”或”#RRGGBB”。 |
int red() const |
返回颜色的红色分量。 |
int green() const |
返回颜色的绿色分量。 |
int blue() const |
返回颜色的蓝色分量。 |
int alpha() const |
返回颜色的透明度分量(Alpha通道)。 |
QRgb rgb() const |
返回颜色的32位整数表示(0xRRGGBB)。 |
QColor darker(int factor = 200) const |
返回一个较暗的颜色,可以通过指定因子调整暗度。 |
QColor lighter(int factor = 150) const |
返回一个较亮的颜色,可以通过指定因子调整亮度。 |
bool isValid() const |
检查颜色是否为有效的颜色。 |
bool setNamedColor(const QString &name) |
设置颜色为指定颜色名。如果颜色名有效,返回 true。 |
bool setRgb(int r, int g, int b, int a = 255) |
设置颜色的RGB值和可选的透明度。如果值有效,返回 true。 |
bool setRgba(qreal r, qreal g, qreal b, qreal a = 1.0) |
设置颜色的RGB浮点值和可选的透明度。如果值有效,返回 true。 |
QString name() const |
返回颜色的名称。如果颜色是基本颜色,则返回基本颜色的名称。 |
QColor toRgb() const |
返回颜色的RGB表示。 |
QColor toHsv() const |
返回颜色的HSV表示。 |
QColor fromRgb(int r, int g, int b, int a = 255) |
静态方法,创建一个颜色对象,使用RGB值和可选的透明度。 |
QColor fromHsv(int h, int s, int v, int a = 255) |
静态方法,创建一个颜色对象,使用HSV值和可选的透明度。 |
这些方法允许你创建、操作和查询颜色对象的各种属性,包括RGB值、透明度、HSV值等。你可以使用这些方法来定制和操作颜色,以满足应用程序的设计需求。
由于我们并不是所有的参数都需要修改,所以可以先通过legend()->font()
先将默认的属性读入,然后再其基础之上对特定的字体和颜色进行属性调整,如下我们分别调整字体颜色;
// ------------------------------------------ |
运行后,我们可以看到图例中的数字变大了,并且居右侧对齐了,颜色则是紫色,如下图所示;
1.1.4 边距设置
边距的设置在多数时候是用不到的,因为Qt中默认的边距已经就很合理了,但是在某些时候边距也需要被调整,调整边距可以通过调用setMargins
函数来实现,该函数需要接收QMargins
类,该类常用于表示矩形边界。
以下是 QMargins
类中常用的方法的说明和概述:
方法 | 描述 |
---|---|
QMargins() |
默认构造函数,创建一个无边距的对象。 |
QMargins(int left, int top, int right, int bottom) |
构造函数,使用指定的边距值创建对象。 |
int left() const |
返回左边距值。 |
void setLeft(int left) |
设置左边距值。 |
int top() const |
返回上边距值。 |
void setTop(int top) |
设置上边距值。 |
int right() const |
返回右边距值。 |
void setRight(int right) |
设置右边距值。 |
int bottom() const |
返回下边距值。 |
void setBottom(int bottom) |
设置下边距值。 |
bool isNull() const |
检查边距是否为零,即是否所有边距值都为零。 |
bool operator==(const QMargins &other) const |
比较两个边距对象是否相等。 |
bool operator!=(const QMargins &other) const |
比较两个边距对象是否不相等。 |
QMargins &operator+=(const QMargins &margins) |
将另一个边距对象的值添加到当前对象。 |
QMargins &operator-=(const QMargins &margins) |
从当前对象的值中减去另一个边距对象的值。 |
QMargins operator+(const QMargins &margins) const |
返回当前对象与另一个边距对象相加的结果。 |
QMargins operator-(const QMargins &margins) const |
返回当前对象与另一个边距对象相减的结果。 |
QMargins
类表示矩形的边距,其包含了四个整数值,分别表示左、上、右、下的边距。这些方法允许你设置和获取边距的各个部分,进行边距的比较和运算等。这在界面布局和绘图等场景中经常用到,用于定义边距和间距。
边界的设置很简单,来看如下代码案例的演示,Qt中默认的边界值应该均为10
这个可以自己去验证。
// ------------------------------------------ |
当运行后,读者可观察图表中的变化,来体会边界值是什么,当然了如果读者设置的负数太大绘图很有可能脱离绘图区;
2.1 序列与坐标轴
2.1.1 QLineSeries序列类
首先在绘图之前,我们必须要先看一下QLineSeries
折线图类,以及QValueAxis
坐标轴类,此处如果读者需要绘制其他的图形,比如折线图中有另一种光滑折线图,则就需要使用QSplineSeries
类,根据不同的图表需要使用不同的绘制类,此处我们就以普通折线图为例,让我们来看一下绘图类中所支持的接口吧。
QLineSeries
是 Qt 中用于绘制折线图的类,下面是关于 QLineSeries
常用的方法的说明和概述:
方法 | 描述 |
---|---|
void append(const QPointF &point) |
向折线系列中追加一个数据点。 |
void append(QPointF &&point) |
向折线系列中追加一个数据点(移动语义版本)。 |
void append(double x, double y) |
向折线系列中追加指定坐标的数据点。 |
void replace(int index, const QPointF &point) |
替换指定索引处的数据点。 |
void replace(int index, double x, double y) |
替换指定索引处的数据点,使用指定坐标。 |
void remove(int index) |
从折线系列中移除指定索引处的数据点。 |
void removePoints(int index, int count) |
从折线系列中移除指定索引开始的指定数量的数据点。 |
void clear() |
清空折线系列中的所有数据点。 |
QPointF at(int index) const |
返回指定索引处的数据点。 |
int count() const |
返回折线系列中数据点的数量。 |
bool isEmpty() const |
检查折线系列是否为空(不包含数据点)。 |
void setPen(const QPen &pen) |
设置绘制折线时使用的笔。 |
QPen pen() const |
返回当前用于绘制折线的笔。 |
void setPointLabelsFormat(const QString &format) |
设置数据点标签的显示格式。 |
QString pointLabelsFormat() const |
返回当前数据点标签的显示格式。 |
void setPointLabelsVisible(bool visible) |
设置是否显示数据点标签。 |
bool pointsVisible() const |
返回是否显示数据点标签。 |
void setUseOpenGL(bool enable) |
设置是否使用OpenGL进行渲染。 |
bool useOpenGL() const |
返回是否使用OpenGL进行渲染。 |
void setColor(const QColor &color) |
设置折线的颜色。 |
QColor color() const |
返回当前折线的颜色。 |
void setOpacity(qreal opacity) |
设置折线的透明度。 |
qreal opacity() const |
返回当前折线的透明度。 |
上述方法提供了一些基本的操作,例如追加、替换、移除数据点,以及设置折线的样式、颜色等属性。你可以根据需要使用这些方法来自定义和控制折线图的外观和行为。
首先我们先来实现对绘制线条的自定义,在创建序列线条时,我们通常会自定义线条的颜色,颜色的自定义可以使用QPen
类来指定,以下是 QPen
类中常用的方法的说明和概述:
方法 | 描述 |
---|---|
QPen() |
默认构造函数,创建一个默认的画笔。 |
QPen(Qt::PenStyle style) |
使用指定的画笔风格创建画笔。 |
QPen(const QColor &color) |
使用指定的颜色创建画笔。 |
QPen(const QBrush &brush, qreal width = 0, Qt::PenStyle style = Qt::SolidLine, Qt::PenCapStyle cap = Qt::SquareCap, Qt::PenJoinStyle join = Qt::BevelJoin) |
使用指定的画刷、宽度、风格、端点样式和连接样式创建画笔。 |
void setColor(const QColor &color) |
设置画笔的颜色。 |
QColor color() const |
返回画笔的颜色。 |
void setStyle(Qt::PenStyle style) |
设置画笔的风格。 |
Qt::PenStyle style() const |
返回画笔的风格。 |
void setWidth(qreal width) |
设置画笔的宽度。 |
qreal width() const |
返回画笔的宽度。 |
void setCapStyle(Qt::PenCapStyle style) |
设置画笔的端点样式。 |
Qt::PenCapStyle capStyle() const |
返回画笔的端点样式。 |
void setJoinStyle(Qt::PenJoinStyle style) |
设置画笔的连接样式。 |
Qt::PenJoinStyle joinStyle() const |
返回画笔的连接样式。 |
void setBrush(const QBrush &brush) |
设置画笔的画刷。 |
QBrush brush() const |
返回画笔的画刷。 |
void setDashPattern(const QVector<qreal> &pattern) |
设置虚线的模式。 |
QVector<qreal> dashPattern() const |
返回虚线的模式。 |
void setDashOffset(qreal offset) |
设置虚线的偏移。 |
qreal dashOffset() const |
返回虚线的偏移。 |
void setCosmetic(bool cosmetic) |
设置画笔是否为“化妆品”笔。当为 true 时,笔将忽略设备的变换,保持笔宽度为一个像素。 |
bool isCosmetic() const |
返回画笔是否为“化妆品”笔。 |
void setTransform(const QTransform &matrix, bool combine = false) |
设置画笔的变换矩阵。 |
QTransform transform() const |
返回画笔的变换矩阵。 |
void setMiterLimit(qreal limit) |
设置斜接连接的限制。 |
qreal miterLimit() const |
返回斜接连接的限制。 |
bool operator==(const QPen &other) const |
比较两个画笔是否相等。 |
bool operator!=(const QPen &other) const |
比较两个画笔是否不相等。 |
这些方法允许你设置和获取画笔的各种属性,如颜色、风格、宽度、样式等。QPen
类用于定义在绘图中如何绘制线条和边框。你可以使用这些方法来自定义画笔,以满足应用程序的设计需求。
当有了QPen
类就可以对颜色进行自定义了,读者需要注意,曲线画笔中有一个setStyle
属性,该属性是用于指定画笔风格的枚举值,常用于设置 QPen
的风格。以下是这些枚举值的说明:
Qt::SolidLine
(实线):- 表示使用实线绘制。
Qt::DashLine
(短划线):- 表示使用短划线绘制,即通过交替的短线和空白段绘制。
Qt::DotLine
(点线):- 表示使用点线绘制,即通过交替的点和空白段绘制。
Qt::DashDotLine
(点划线):- 表示使用点划线绘制,即通过交替的点、短划线和空白段绘制。
这些枚举值通常用于设置画笔的风格,当有了这些前置条件以后,相信读者能更容易地理解曲线序列是如何被创建出来的了,如下代码则是一个完整版的创建流程,读者可自行参考学习;
// ------------------------------------------ |
运行上述绘制代码,读者可以看到如下图所示的案例,这里之所以很乱是为了更好的演示函数功能,读者可以自行关闭这些选项后依次观察效果;
2.1.2 QValueAxis坐标轴类
接着我们就需要设置图表中的坐标轴参数,本例中我们使用QValueAxis
类的坐标轴,这是数值型坐标轴,其刚好可以与QLineSeries
配合使用,当如Qt中提供了许多坐标轴,但他们都是从QAbstractAxis
类继承而来的。
QValueAxis
是用于处理数值轴的类,通常用于折线图、散点图等图表类型。以下是关于 QValueAxis
常用的方法的说明和概述:
方法 | 描述 |
---|---|
void setRange(qreal min, qreal max) |
设置轴的数值范围。 |
void setTickCount(int count) |
设置轴上的刻度数量。 |
void setMinorTickCount(int count) |
设置轴上每个刻度之间的小刻度数量。 |
void setLabelFormat(const QString &format) |
设置刻度标签的显示格式。 |
void setLabelsVisible(bool visible) |
设置是否显示刻度标签。 |
void setTitleText(const QString &title) |
设置轴的标题。 |
void setTitleVisible(bool visible) |
设置是否显示轴的标题。 |
void setGridLineVisible(bool visible) |
设置是否显示网格线。 |
void setGridLineColor(const QColor &color) |
设置网格线的颜色。 |
void setGridLinePen(const QPen &pen) |
设置用于绘制网格线的笔。 |
void setLinePen(const QPen &pen) |
设置轴线的笔。 |
qreal min() const |
返回轴的最小值。 |
qreal max() const |
返回轴的最大值。 |
int tickCount() const |
返回轴上的刻度数量。 |
int minorTickCount() const |
返回轴上每个刻度之间的小刻度数量。 |
QString labelFormat() const |
返回刻度标签的显示格式。 |
bool isLabelsVisible() const |
返回是否显示刻度标签。 |
QString titleText() const |
返回轴的标题。 |
bool isTitleVisible() const |
返回是否显示轴的标题。 |
bool isGridLineVisible() const |
返回是否显示网格线。 |
QColor gridLineColor() const |
返回网格线的颜色。 |
QPen gridLinePen() const |
返回用于绘制网格线的笔。 |
QPen linePen() const |
返回轴线的笔。 |
这些方法提供了对数值轴的各种设置和属性获取,包括范围、刻度、标签、标题、网格线等。你可以使用这些方法来定制数值轴以满足你图表的需求。
如下是坐标轴的常用配置参数,读者可自行选择不同的函数设置使用,其完整代码如下所示;
// ----------------------------------------------- |
最后是对数据进行初始化,因为初始化数据之前需要拿到series
对象的指针,当得到该指针后,就可以通过调用append()
方法或者是<<
符号进行数据的追加操作,每次递增intv
循环直到cnt
计数结束;
// --------------------------------------------------- |
运行后读者可以看到如下图所示的输出效果;