折线图折线图在 Qt Charts 中绘制折线图主要涉及以下核心组件●QLineSeries用于存储折线图的数据点。●QChart图表的核心对象管理所有的系列、坐标轴和图例。●QChartView用于在界面上显示 QChart 的视图组件类似于 QGraphicsView。●QValueAxis数值坐标轴用于在图表中显示数值范围。Qt Charts的方法不复杂我们通过案例快速学习示例场景实现这样一个折线图我们将创建一个显示某个产品销量随时间变化的折线图创建一个项目LineSeries在pro中添加chartsQT core gui charts完成mainwindow的声明class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent nullptr); ~MainWindow(); private: Ui::MainWindow *ui; // 用于在界面上显示 QChart 的视图组件类似于 QGraphicsView QChartView *chartView; // 图表的核心对象管理所有的系列、坐标轴和图例。 QChart *chart; // 用于存储折线图的数据点 QLineSeries *series; // 数值坐标轴用于在图表中显示数值范围 QValueAxis *axisX; // y轴坐标 QValueAxis *axisY; };在构造函数中我们创建折线图并且添加数据点分别设置横纵坐标范围MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); // 创建折线系列 series new QLineSeries(); //设置系列名字 series-setName(产品销量); // 添加数据点 (X: 时间, Y: 销量) series-append(0, 1); series-append(1, 3); series-append(2, 2); series-append(3, 5); series-append(4, 4); // 创建图表 chart new QChart(); //将数据添加到图表中 chart-addSeries(series); //设置图表名字 chart-setTitle(产品销量折线图示例); //设置图例可见 chart-legend()-setVisible(true); //设置图例在底部 chart-legend()-setAlignment(Qt::AlignBottom); // 创建坐标轴 axisX new QValueAxis(); //设置x轴坐标标题 axisX-setTitleText(时间); //设置x轴刻度文本显示的格式 axisX-setLabelFormat(%d); //设置x轴的刻度数量 axisX-setTickCount(5); //设置x轴的坐标范围 axisX-setRange(0, 4); //设置纵坐标 axisY new QValueAxis(); axisY-setTitleText(销量); axisY-setLabelFormat(%d); axisY-setTickCount(6); axisY-setRange(0, 5); // 将坐标轴添加到图表 chart-addAxis(axisX, Qt::AlignBottom); chart-addAxis(axisY, Qt::AlignLeft); // 连接系列与坐标轴 series-attachAxis(axisX); series-attachAxis(axisY); // 创建图表视图 chartView new QChartView(chart); chartView-setRenderHint(QPainter::Antialiasing); // 将图表视图添加到主窗口的布局中 QVBoxLayout *layout new QVBoxLayout(); layout-addWidget(chartView); // 设置中央小部件的布局 QWidget *widget new QWidget(); widget-setLayout(layout); setCentralWidget(widget); }折线图的定制和美化(拓展)设置图表主题Qt Charts 提供了多种内置主题可以快速改变图表的整体风格。// 设置图表主题为黑暗主题 chart-setTheme(QChart::ChartThemeDark); // 可选主题列表 // ChartThemeLight, ChartThemeBlueCerulean, ChartThemeBrownSand, // ChartThemeBlueNcs, ChartThemeHighContrast, ChartThemeBlueIcy自定义坐标轴设置坐标轴标题axisX-setTitleText(时间 (月)); axisY-setTitleText(销量 (单位));设置坐标轴范围和刻度axisX-setRange(0, 12); // 时间范围从0到12 axisX-setTickCount(13); // 每个月一个刻度 axisY-setRange(0, 100); axisY-setTickCount(11); // 每10单位一个刻度设置折线颜色和宽度QPen pen series-pen(); pen.setColor(Qt::red); // 设置折线颜色为红色 pen.setWidth(2); // 设置折线宽度 series-setPen(pen);设置折线曲线平滑默认情况下折线是直线连接的。要实现曲线平滑可以使用QSplineSeries代替QLineSeries。#include QtCharts/QSplineSeries QSplineSeries *splineSeries new QSplineSeries(); splineSeries-setName(平滑曲线); splineSeries-append(0, 1); splineSeries-append(1, 3); splineSeries-append(2, 2); // 添加更多数据点 chart-addSeries(splineSeries); splineSeries-attachAxis(axisX); splineSeries-attachAxis(axisY);平滑曲线示例大家可以自己制作数据做出如下的图示答案MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); //创建平滑曲线系列 series new QSplineSeries(); //设置系列的名字 series-setName(产品销量); //添加数据点 series-append(1,3); series-append(2,2); series-append(3,5); series-append(4,4); series-append(5,3); series-append(6,2); series-append(7,5); series-append(8,4); series-append(9,9); series-append(10,8); series-append(11,7); series-append(12,4); //设置画笔颜色 QPen pen series-pen(); pen.setColor(Qt::red); pen.setWidth(2); series-setPen(pen); //创建图表 chart new QChart(); //将数据添加到图表中 chart-addSeries(series); //设置图表名字 chart-setTitle(产品销量平滑曲线图示例); //设置图例可见 chart-legend()-setVisible(true); //设置图例在底部 chart-legend()-setAlignment(Qt::AlignBottom); //创建坐标轴 axisX new QValueAxis(); axisX-setTitleText(时间(月)); //表示1到12个月 axisX-setRange(1,12); //刻度数量为12 axisX-setTickCount(12); //设置刻度的文本 axisX-setLabelFormat(%d); //创建坐标轴 axisY new QValueAxis(); axisY-setTitleText(销量(万台)); //表示销量范围 axisY-setRange(0,10); //刻度数量为10 axisY-setTickCount(10); //设置刻度的文本 axisY-setLabelFormat(%d); //将坐标轴添加到图表 chart-addAxis(axisX, Qt::AlignBottom); chart-addAxis(axisY,Qt::AlignLeft); //连接系列和坐标系 series-attachAxis(axisX); series-attachAxis(axisY); //创建图表 chartView new QChartView(chart); chartView-setRenderHint(QPainter::Antialiasing); //创建布局并且放入chartview auto* widget new QWidget(this); auto * layout new QVBoxLayout(widget); setCentralWidget(widget); layout-addWidget(chartView); this-resize(800,600); }添加散点图可以通过设置QScatterSeries来添加数据点标记。#include QtCharts/QScatterSeries // 创建散点系列 QScatterSeries *scatterSeries new QScatterSeries(); scatterSeries-setName(数据点); // 设置数据点为圆形 scatterSeries-setMarkerShape(QScatterSeries::MarkerShapeCircle); scatterSeries-setMarkerSize(8.0); scatterSeries-setColor(Qt::blue); // 添加数据点 scatterSeries-append(0, 1); scatterSeries-append(1, 3); // 添加更多数据点 chart-addSeries(scatterSeries); scatterSeries-attachAxis(axisX); scatterSeries-attachAxis(axisY);QScatterSeries::MarkerShapeCircle这是一个枚举值表示数据点的形状为圆形。Qt Charts 提供了多种形状选项例如MarkerShapeCircle圆形MarkerShapeRectangle矩形MarkerShapeDiamond菱形MarkerShapeStar星形MarkerShapeCross十字形MarkerShapePixmap自定义图像示例在之前的曲线图基础上添加几个散点散点的数据和曲线的数据一样要求实现如下效果实现细节在源代码的基础上也就是MainWindow的构造函数里继续添加散点图的创建并加入到chart中。注意不要忘了将散点图系列绑定到坐标MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){ //... 前面省略 //创建散点系列 QScatterSeries* scatterSeries new QScatterSeries(); scatterSeries-setName(数据散点); scatterSeries-setMarkerShape(QScatterSeries::MarkerShapeCircle); //添加数据点 scatterSeries-append(1,3); scatterSeries-append(2,2); scatterSeries-append(3,5); scatterSeries-append(4,4); scatterSeries-append(5,3); scatterSeries-append(6,2); scatterSeries-append(7,5); scatterSeries-append(8,4); scatterSeries-append(9,9); scatterSeries-append(10,8); scatterSeries-append(11,7); scatterSeries-append(12,4); //加入散点 chart-addSeries(scatterSeries); //绑定到坐标 scatterSeries-attachAxis(axisX); scatterSeries-attachAxis(axisY); }显示悬停提示在用户悬停在数据点上时显示详细信息可以使用QToolTip或自定义工具提示。// 在主窗口类中添加槽函数 private slots: void handlePointHovered(const QPointF point, bool state); // 在构造函数中连接信号 connect(series, QSplineSeries::hovered, this, MainWindow::handlePointHovered); // 实现槽函数 #include QToolTip void MainWindow::handlePointHovered(const QPointF point, bool state) { if (state) { QString tooltipText QString(时间: %1 月\n销量: %2 单位).arg(point.x()).arg(point.y()); QToolTip::showText(QCursor::pos(), tooltipText, chartView); } else { QToolTip::hideText(); } }hovered信号参数解释const QPointF point:类型:QPointF是一个表示二维点的类包含两个浮点数x和y坐标。意义: 这个参数表示鼠标悬停的点的坐标。在散点图中这个点通常对应于某个数据点的值。point.x()表示该点在 X 轴上的值point.y()表示该点在 Y 轴上的值。bool state:类型: 布尔值bool。意义: 这个参数表示鼠标是否悬停在某个数据点上。如果state为true这意味着鼠标正在悬停在数据点上如果为false则表示鼠标离开了该数据点。这个参数用于控制工具提示的显示和隐藏。确保启用系列的悬停事件series-setPointsVisible(true); // 启用数据点可见演示案例基于之前的平滑曲线和散点图我们支持鼠标悬浮显示数据提示的效果实现思路在mainwindow的声明里添加public slots: //捕获鼠标悬浮事件 void handlePointHovered(const QPointF point, bool state);在构造函数里添加//开启数据点可视 series-setPointsVisible(true); //连接信号和槽,捕获悬浮信号 connect(series, QSplineSeries::hovered, this, MainWindow::handlePointHovered); scatterSeries-setPointsVisible(true); connect(scatterSeries, QScatterSeries::hovered, this, MainWindow::handlePointHovered);实现槽函数void MainWindow::handlePointHovered(const QPointF point, bool state) { if (state) { QString tooltipText QString(时间: %1 月\n销量: %2 单位).arg(point.x()).arg(point.y()); QToolTip::showText(QCursor::pos(), tooltipText, chartView); } else { QToolTip::hideText(); } }设定背景和网格线设置图表背景颜色chart-setBackgroundBrush(QBrush(Qt::white)); // 设置背景为白色设置网格线axisX-setGridLineVisible(true); axisY-setGridLineVisible(true);启用缩放和平移QChartView提供了内置的缩放和平移功能可以通过设置橡皮筋RubberBand来启用。// 启用矩形缩放 chartView-setRubberBand(QChartView::RectangleRubberBand); // 或者启用水平/垂直缩放 // chartView-setRubberBand(QChartView::HorizontalRubberBand); // chartView-setRubberBand(QChartView::VerticalRubberBand);用户可以通过鼠标拖拽来选择缩放区域或通过鼠标滚轮进行缩放。动态更新折线图数据我们可以做一个动态更新正弦波的案例将通过以下步骤实现动态正弦曲线的绘制创建QLineSeries并初始化正弦曲线数据。将系列添加到QChart。使用QTimer定时更新数据点实现动态效果。设置坐标轴、图表样式等。要求达到如下图效果开发思路创建项目sinline, 在mainwindow中声明各参数class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent nullptr); ~MainWindow(); private: Ui::MainWindow *ui; //Qt Charts成员 QChartView * chartView; QChart * chart; QSplineSeries * series; QValueAxis* axisX; QValueAxis* axisY; QTimer* timer; //当前的角度 double currentAngle; };在构造函数创建图表MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { //创建视图坐标轴等 chartView new QChartView(this); chart new QChart(); series new QSplineSeries(); axisX new QValueAxis(); axisY new QValueAxis(); //创建定时器 timer new QTimer(this); //初始弧度为0 currentAngle 0.0; ui-setupUi(this); //为保证数据足够充分才能显示出更准确的曲线 //所以将一个周期定位2*M_PI将其分成100份作为x坐标 auto pointsCount 100; //将弧度划分100分 auto step 2*M_PI/pointsCount; //计算每个点对应的弧度 for(int i 0; i pointsCount; i){ double angle i * step; double sineValue qSin(angle); series-append(angle,sineValue); } //设置series名字 series-setName(正弦波); //将系列添加到图表 chart-addSeries(series); //设置图表标题 chart-setTitle(动态正弦曲线示例); //显示图例 chart-legend()-setVisible(true); //设置坐标轴 axisX-setTitleText(角度(弧度)); //设置范围 axisX-setRange(0,2*M_PI); //设置坐标轴文本样式 axisX-setLabelFormat(%.2f); //设置刻度数 axisX-setTickCount(10); axisY-setTitleText(正弦值); axisY-setRange(-1.5, 1.5); axisY-setLabelFormat(%.1f); axisY-setTickCount(5); // 将坐标轴添加到图表 chart-addAxis(axisX, Qt::AlignBottom); chart-addAxis(axisY, Qt::AlignLeft); // 连接系列与坐标轴 series-attachAxis(axisX); series-attachAxis(axisY); // 设置图表主题 chart-setTheme(QChart::ChartThemeDark); // 创建图表视图 chartView-setChart(chart); chartView-setRenderHint(QPainter::Antialiasing); // 设置布局 QVBoxLayout *layout new QVBoxLayout(); layout-addWidget(chartView); QWidget *widget new QWidget(); widget-setLayout(layout); setCentralWidget(widget); resize(1000,600); }此时运行程序能看到静态的正弦曲线了接下来我们在构造函数中启动定时器每隔50ms触发依次回调函数, 更新坐标轴数据信息MainWindow::MainWindow(): QMainWindow(parent), ui(new Ui::MainWindow){ //...省略之前的图表操作 // 配置定时器 connect(timer, QTimer::timeout, this, MainWindow::updateSineWave); // 每50毫秒更新一次 timer-start(50); } //实现定时器函数 void MainWindow::updateSineWave() { // 增加当前角度 currentAngle 0.05; // 以步长0.05弧度递增 // 移动角度范围为 [currentAngle, currentAngle 2π] // 清空旧数据 series-clear(); // 生成新的正弦曲线数据 const int pointsCount 100; const double step (2 * M_PI) / pointsCount; for (int i 0; i pointsCount; i) { double angle currentAngle i * step; double sineValue qSin(angle); series-append(angle, sineValue); } // 更新X轴范围 axisX-setRange(currentAngle, currentAngle 2 * M_PI); }再次运行就可以看到正弦曲线动起来了。