Qt图表功能学习
1. 项目概述
本项目展示了如何使用Qt Charts模块创建图表,实现温度与时间的曲线关系展示。Qt Charts是Qt提供的一个强大的图表绘制模块,可以方便地创建各种类型的图表,如折线图、曲线图、柱状图、饼图等。
1.1 项目结构
47/
├── 47.pro # 项目配置文件
├── main.cpp # 主函数入口
├── widget.h # Widget类头文件
├── widget.cpp # Widget类实现文件
└── widget.ui # 界面设计文件
1.2 功能特点
- 创建温度与时间的曲线图表
- 设置坐标轴范围和标题
- 自定义曲线样式和颜色
- 使用QSplineSeries创建平滑曲线
2. 代码实现
2.1 项目配置文件 (47.pro)
qmake
QT += core gui charts
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
关键点说明:
QT += charts
- 添加Qt Charts模块支持,这是使用图表功能的必要配置
2.2 主函数 (main.cpp)
cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
2.3 Widget类头文件 (widget.h)
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QChart> // 图表类
#include <QChartView> // 图表视图类
QT_CHARTS_USE_NAMESPACE // using namespace QT_CHARTS_NAMESPACE
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
关键点说明:
#include <QChart>
和#include <QChartView>
- 包含图表相关的头文件QT_CHARTS_USE_NAMESPACE
- 使用Qt Charts命名空间,避免每次使用图表类时都要加上命名空间前缀
2.4 Widget类实现文件 (widget.cpp)
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QValueAxis> // 数值坐标轴
#include <QSplineSeries> // 曲线
//#include <QLineSeries> // 折线
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 1.创建一个图表视图
// QChartView *chartView = new QChartView();
// 2.创建一个图表
QChart *chart = new QChart();
// 3.创建坐标轴
QValueAxis *valueAxisX = new QValueAxis();
QValueAxis *valueAxisY = new QValueAxis();
// 4.设置坐标轴的范围
valueAxisX->setRange(0, 5000);
valueAxisY->setRange(0, 100);
// 5.设置坐标轴的标题和显示的格式
valueAxisX->setTitleText("时间/ms");
valueAxisY->setTitleText("温度/°C");
valueAxisX->setLabelFormat("%d");
valueAxisY->setLabelFormat("%d");
// 设置xy的显示的格式
// valueAxisX->setTickCount(10);
// valueAxisY->setTickCount(10);
// 6.图表添加坐标轴
chart->createDefaultAxes();
chart->addAxis(valueAxisX, Qt::AlignBottom);
chart->addAxis(valueAxisY, Qt::AlignLeft);
// 7.设置图表的标题以及图例显示是否需要
chart->setTitle("温度与时间曲线");
chart->legend()->setVisible(false);
// 8.创建曲线对象添加它的点,设置曲线的颜色
QSplineSeries *splineSeries = new QSplineSeries();
splineSeries->append(0, 50);
splineSeries->append(1000, 60);
splineSeries->append(2000, 80);
splineSeries->append(3000, 50);
splineSeries->append(4000, 30);
splineSeries->append(5000, 80);
QPen pen(QColor(0xff5566));
splineSeries->setPen(pen);
// 9.图表添加曲线
chart->addSeries(splineSeries);
// 10.!!!!将曲线的数据与坐标轴相连!!!!注意,这个要在图表添加曲线之后
// 附属到坐标轴上面去
splineSeries->attachAxis(valueAxisX);
splineSeries->attachAxis(valueAxisY);
// 11.将图表放置于图表视图
ui->chartView->setChart(chart);
}
Widget::~Widget()
{
delete ui;
}
关键点说明:
-
图表创建流程:
- 创建图表对象
QChart
- 创建坐标轴
QValueAxis
- 设置坐标轴范围和标题
- 将坐标轴添加到图表
- 设置图表标题和图例
- 创建曲线并添加数据点
- 设置曲线样式
- 将曲线添加到图表
- 将曲线与坐标轴关联
- 将图表设置到图表视图
- 创建图表对象
-
坐标轴设置:
setRange(min, max)
- 设置坐标轴范围setTitleText(text)
- 设置坐标轴标题setLabelFormat(format)
- 设置坐标轴标签格式setTickCount(count)
- 设置刻度数量
-
曲线设置:
QSplineSeries
- 创建平滑曲线append(x, y)
- 添加数据点setPen(pen)
- 设置曲线样式attachAxis(axis)
- 将曲线与坐标轴关联
2.5 界面设计文件 (widget.ui)
xml
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>QChart图表示例</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QChartView" name="chartView"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QChartView</class>
<extends>QGraphicsView</extends>
<header>qchartview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
关键点说明:
- 界面使用垂直布局,包含一个标签和一个图表视图
QChartView
是一个自定义控件,继承自QGraphicsView
- 需要包含头文件
qchartview.h
3. Qt Charts模块详解
3.1 常用图表类型
类名 | 描述 | 用途 |
---|---|---|
QLineSeries | 折线图 | 显示离散数据点之间的直线连接 |
QSplineSeries | 曲线图 | 显示平滑曲线连接的数据点 |
QScatterSeries | 散点图 | 显示不连接的离散数据点 |
QBarSeries | 柱状图 | 显示分类数据的柱状表示 |
QPieSeries | 饼图 | 显示数据占比的圆形表示 |
QAreaSeries | 面积图 | 显示数据区域填充的图表 |
3.2 坐标轴类型
类名 | 描述 | 用途 |
---|---|---|
QValueAxis | 数值坐标轴 | 显示数值型数据 |
QDateTimeAxis | 日期时间坐标轴 | 显示日期和时间 |
QCategoryAxis | 类别坐标轴 | 显示分类数据 |
QLogValueAxis | 对数坐标轴 | 显示对数刻度 |
4. 实现步骤详解
4.1 添加Charts模块
在项目文件(.pro)中添加:
qmake
QT += charts
4.2 包含必要的头文件
cpp
#include <QChart>
#include <QChartView>
#include <QValueAxis>
#include <QSplineSeries> // 或其他系列类型
QT_CHARTS_USE_NAMESPACE // 使用Qt Charts命名空间
4.3 创建图表的基本步骤
- 创建图表和坐标轴
cpp
// 创建图表
QChart *chart = new QChart();
// 创建坐标轴
QValueAxis *axisX = new QValueAxis();
QValueAxis *axisY = new QValueAxis();
// 设置坐标轴范围
axisX->setRange(0, 10);
axisY->setRange(0, 100);
// 设置坐标轴标题
axisX->setTitleText("X轴");
axisY->setTitleText("Y轴");
// 添加坐标轴到图表
chart->addAxis(axisX, Qt::AlignBottom);
chart->addAxis(axisY, Qt::AlignLeft);
- 创建数据系列并添加数据
cpp
// 创建曲线系列
QSplineSeries *series = new QSplineSeries();
// 添加数据点
series->append(0, 10);
series->append(1, 20);
series->append(2, 30);
// ...
// 设置系列名称(用于图例)
series->setName("数据系列1");
// 自定义系列外观
QPen pen(QColor(0x00, 0x80, 0x80));
pen.setWidth(2);
series->setPen(pen);
// 添加系列到图表
chart->addSeries(series);
// 将系列附加到坐标轴
series->attachAxis(axisX);
series->attachAxis(axisY);
- 设置图表属性
cpp
// 设置图表标题
chart->setTitle("我的图表");
// 设置图例可见性
chart->legend()->setVisible(true);
// 设置图例位置
chart->legend()->setAlignment(Qt::AlignBottom);
// 设置图表主题
chart->setTheme(QChart::ChartThemeBlueCerulean);
// 设置动画
chart->setAnimationOptions(QChart::AllAnimations);
- 将图表添加到视图
cpp
// 方法1:使用已有的QChartView控件(如UI设计中添加的)
ui->chartView->setChart(chart);
// 方法2:创建新的QChartView
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing); // 抗锯齿
5. 常用功能示例
5.1 动态添加数据点
cpp
// 假设我们有一个定时器,每秒添加一个新的数据点
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [=]() {
// 获取最后一个点的x值
qreal lastX = 0;
if (!series->points().isEmpty()) {
lastX = series->points().last().x();
}
// 生成新的数据点
qreal newX = lastX + 1;
qreal newY = QRandomGenerator::global()->bounded(100); // 随机值
// 添加到系列
series->append(newX, newY);
// 如果需要,调整X轴范围以显示最新数据
if (newX > axisX->max()) {
axisX->setRange(axisX->min() + 1, newX);
}
});
// 启动定时器,每秒触发一次
timer->start(1000);
5.2 多个数据系列
cpp
// 创建第一个系列
QSplineSeries *series1 = new QSplineSeries();
series1->setName("温度1");
series1->append(0, 10);
series1->append(1, 20);
// ...
// 创建第二个系列
QSplineSeries *series2 = new QSplineSeries();
series2->setName("温度2");
series2->append(0, 15);
series2->append(1, 25);
// ...
// 设置不同颜色
series1->setPen(QPen(QColor(0xff, 0x55, 0x66), 2));
series2->setPen(QPen(QColor(0x55, 0x66, 0xff), 2));
// 添加到图表
chart->addSeries(series1);
chart->addSeries(series2);
// 附加到坐标轴
series1->attachAxis(axisX);
series1->attachAxis(axisY);
series2->attachAxis(axisX);
series2->attachAxis(axisY);
5.3 自定义图表主题
cpp
// 设置预定义主题
chart->setTheme(QChart::ChartThemeDark); // 深色主题
// 或者自定义图表背景
QLinearGradient backgroundGradient;
backgroundGradient.setStart(QPointF(0, 0));
backgroundGradient.setFinalStop(QPointF(0, 1));
backgroundGradient.setColorAt(0.0, QRgb(0x2F2F3F));
backgroundGradient.setColorAt(1.0, QRgb(0x1F1F2F));
backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
chart->setBackgroundBrush(backgroundGradient);
// 自定义图表边框
chart->setBackgroundPen(QPen(QRgb(0x3F3F4F)));
5.4 图表交互
cpp
// 启用图表交互功能
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
// 启用缩放和平移
chartView->setRubberBand(QChartView::RectangleRubberBand);
chartView->setInteractive(true);
// 处理点击事件(需要自定义QChartView子类)
class CustomChartView : public QChartView {
public:
CustomChartView(QChart *chart, QWidget *parent = nullptr)
: QChartView(chart, parent) {}
protected:
void mousePressEvent(QMouseEvent *event) override {
QPointF pos = chart()->mapToValue(event->pos());
qDebug() << "Clicked at:" << pos;
// 查找最近的点
for (auto series : chart()->series()) {
QXYSeries *xySeries = qobject_cast<QXYSeries*>(series);
if (xySeries) {
// 查找最近的点逻辑...
}
}
QChartView::mousePressEvent(event);
}
};