一、介绍场景
动态查看数据变化,或者了解数据发展趋势,让数据可以形象直观展现出来,这里推荐使用折线图的方式展现,本文抛砖引玉,简单实现一个实例,效果图如下:
二、实现步骤
1、charts组件
(1)、这里用来绘制图表,引入QT中的charts组件;首先要确保安装了组件QT Charts;在pro文件中添加如下代码
QT += charts
(2)、这里主要用的类为QChart为图表绘制画布; QChartView为图表绘制相框,其位于QChart之上;QDateTimeAxis为时间坐标轴;QValueAxis为数值坐标轴;QLineSeries为折线数据线;
2、核心代码
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QString>
#include <QLabel>//#include <QtCharts/QChartGlobal>
#include <QtCharts/QChart>
#include <QtCharts/QChartView> // 图标相框
#include <QtCharts/QLineSeries> // 绘制线
#include <QtCharts/QValueAxis> // 坐标轴
#include <QtCharts/QDateTimeAxis> // 时间坐标轴QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass colorForm;// 使用 QChart,必须包含这个名字空间,不然,就要加名字空间
// 例如:QtCharts::QChart
QT_CHARTS_USE_NAMESPACEtypedef struct tagTipsColor
{QString strColor{""};QString strTipsTxt{""};tagTipsColor(){}tagTipsColor(QString color, QString strTxt){strColor = color;strTipsTxt = strTxt;}
}TAGTIPSCOLOR;// 绘制折线数据
typedef struct LinePtProgress
{__int64 x; // 使用word类型,记录时间,int y; // 具体数值QString yColor{""};LinePtProgress(){}LinePtProgress(__int64 inX, int inY, QString inYColor="#B3F4AB"){x = inX;y = inY;yColor = inYColor;}
}LPTPROGRESS;class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public:void initData();void initUi();protected:void resizeEvent(QResizeEvent* event) override;void showEvent(QShowEvent *event) override;private:void initChart();// 创建仿真数据单元void createTempDataUnit(QVector<QVector<LPTPROGRESS>>& vecArrData, QStringList& vecColor,const int unitSize, const int size);// 造仿真数据void createTempData(QVector<LPTPROGRESS>& arrData, QString strColor, const int size, const int key);// 设置颜色图例void setColorLayout(QVector<colorForm*> vecForm);// 绘制数据线void drawDataLine(QVector<QVector<LPTPROGRESS>>& vecPtInfo);// 设置样式void loadStyleSheet();private:Ui::Widget *ui;QVector<TAGTIPSCOLOR> m_arrColor;QVector<QVector<LPTPROGRESS>> m_vecArrData;QChart* m_chart{nullptr};QChartView* m_chartView{nullptr};QDateTimeAxis * m_axisX{nullptr}; // X轴QValueAxis* m_axisY{nullptr}; // Y轴QLabel* m_targetLabel{nullptr};
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"#include <QDateTime>
#include <QRandomGenerator>
#include <colorform.h>
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);initChart();initData();
}Widget::~Widget()
{delete ui;
}void Widget::initData()
{m_arrColor << TAGTIPSCOLOR() << TAGTIPSCOLOR() <<TAGTIPSCOLOR();m_arrColor[0].strColor = "#BA4CB9";m_arrColor[0].strTipsTxt = "语文";m_arrColor[1].strColor = "#268BFF";m_arrColor[1].strTipsTxt = "数学";m_arrColor[2].strColor = "#FF6B26";m_arrColor[2].strTipsTxt = "外语";QStringList colorStrLst;colorStrLst.push_back("#BA4CB9");colorStrLst.push_back("#268BFF");colorStrLst.push_back("#FF6B26");const int SIZE = 90;createTempDataUnit(m_vecArrData, colorStrLst, colorStrLst.size(), SIZE);initUi();
}void Widget::initUi()
{ui->label_Title->setText("语数外成绩走势图");QVector<colorForm *> vecColorForm;for (int i = 0; i < m_arrColor.size(); i++){colorForm* pForm = new colorForm(m_arrColor[i].strColor, m_arrColor[i].strTipsTxt, this);vecColorForm.push_back(pForm);}setColorLayout(vecColorForm);drawDataLine(m_vecArrData);
}void Widget::resizeEvent(QResizeEvent *event)
{Q_UNUSED(event)loadStyleSheet();int viewX = m_chartView->x();int viewY = m_chartView->y();int viewW = m_chartView->width();if(m_targetLabel){m_targetLabel->move(viewX + viewW/3, viewY+20);}
}void Widget::showEvent(QShowEvent *event)
{Q_UNUSED(event)int viewX = m_chartView->x();int viewY = m_chartView->y();int viewW = m_chartView->width();if(m_targetLabel){m_targetLabel->move(viewX + viewW/3, viewY+20);}
}void Widget::initChart()
{m_chart = new QChart();m_chart->setBackgroundBrush(QBrush(Qt::transparent));// 获取X轴m_axisX = new QDateTimeAxis(this);// 设置日期显示格式为年 - 月 - 日m_axisX->setFormat("yyyy.MM.dd");m_axisX->setGridLineVisible(false);// 去掉网格线// 设置 X 轴文本颜色为红色,字体大小为 12QFont xAxisFont = m_axisX->labelsFont();xAxisFont.setPixelSize(12);m_axisX->setLabelsColor(QColor(158, 158, 158));m_axisX->setLabelsFont(xAxisFont);m_axisY = new QValueAxis();m_axisY->setGridLineVisible(false);// 去掉网格线// 设置 Y 轴文本颜色,字体大小为 12QFont yAxisFont = m_axisY->labelsFont();yAxisFont.setPixelSize(12);m_axisY->setLabelsColor(QColor(158, 158, 158));m_axisY->setLabelsFont(yAxisFont);// 将轴添加到图表中m_chart->addAxis(m_axisX, Qt::AlignBottom);m_chart->addAxis(m_axisY, Qt::AlignLeft);// 设置图例的可见性m_chart->legend()->setVisible(false);// 设置图例的对齐方式m_chart->legend()->setAlignment(Qt::AlignBottom);// 创建一个QChartView对象,用于显示QChartm_chartView = new QChartView(m_chart, this);m_chartView->setStyleSheet("background: transparent;");// 设置抗锯齿,使图表显示更平滑m_chartView->setRenderHint(QPainter::Antialiasing);ui->mainVLayout->addWidget(m_chartView, 10);m_targetLabel = new QLabel(this);
}void Widget::createTempDataUnit(QVector<QVector<LPTPROGRESS> > &vecArrData, QStringList& vecColor, const int unitSize, const int size)
{for(int i = 0; i < unitSize; i++){QVector<LPTPROGRESS> arrData;QString str = vecColor[i];createTempData(arrData, str, size, i);vecArrData.push_back(arrData);}
}void Widget::createTempData(QVector<LPTPROGRESS> &arrData, QString strColor, const int size, const int key)
{QVector<int> data;// 先随机生成 90 个数并计算总和for (int i = 0; i < size; ++i) {qint64 b = QDateTime::currentMSecsSinceEpoch();// 使用时间戳作为种子初始化随机数生成器QRandomGenerator generator(b);// 生成一个0到300之间的随机整数int addNum = generator.bounded(100);if(addNum < 60){int t = addNum / 10;addNum += (6 - t)*10;}data.push_back(addNum); // 生成 60 到 99 之间的随机数}QDateTime currentTime(QDate(2024, 10, 1), QTime(12, 0, 0)); // 每隔一分钟一个数据点for (int i = 0; i < size; i++){qint64 msecsSinceEpoch = currentTime.toMSecsSinceEpoch();LPTPROGRESS itemData(msecsSinceEpoch, data[i], strColor);currentTime = currentTime.addDays(1);arrData.push_back(itemData);}
}void Widget::setColorLayout(QVector<colorForm *> vecForm)
{int idx = 0;int r = 0;int maxCol = 0;for (const auto& pForm:vecForm){if(!pForm){continue;}r = idx / 3;int col = idx % 3;if(col+3 > maxCol){maxCol = col+3;}ui->subGLayout->addWidget(pForm, r, col+2);++idx;}
}void Widget::drawDataLine(QVector<QVector<LPTPROGRESS> > &vecVecPtInfo)
{int ptLineUnit = vecVecPtInfo.size();if(0 == ptLineUnit){qDebug() << "drawDataLine data empty";return;}QLineSeries *targetseries = new QLineSeries(this);QPen pen = targetseries->pen();pen.setStyle(Qt::DashLine); // 设置为虚线样式pen.setColor(Qt::green); // 设置线条颜色pen.setWidth(2); // 设置线条宽度targetseries->setPen(pen);QFont font;font.setPixelSize(12);m_targetLabel->setFont(font);QPalette palette = m_targetLabel->palette();palette.setColor(QPalette::WindowText, Qt::green); // 设置文本颜色为红色m_targetLabel->setPalette(palette);m_targetLabel->setText("满分:100");bool targetDraw = false;for(const auto& vecPtInfo:vecVecPtInfo){if(0 == vecPtInfo.size()){qDebug() << "draw unit DataLine data empty";continue;}QLineSeries *addseries = new QLineSeries(this);QPen pen1(QColor(vecPtInfo[0].yColor));pen1.setWidth(2); // 设置折线宽度为 2 像素addseries->setPen(pen1);__int64 minX = vecPtInfo[0].x;__int64 maxX = vecPtInfo[0].x;bool hasDrawTarget = false;for(const auto& ptInfo:vecPtInfo){int pY = ptInfo.y;addseries->append(ptInfo.x, pY);if(targetseries && !targetDraw){targetseries->append(ptInfo.x, 100);hasDrawTarget = true;}if(minX > ptInfo.x){minX = ptInfo.x;}if(maxX < ptInfo.x){maxX = ptInfo.x;}}if(!targetDraw){targetDraw = hasDrawTarget;}QDateTime startDate = QDateTime::fromMSecsSinceEpoch(minX);QDateTime endDate = QDateTime::fromMSecsSinceEpoch(maxX);m_axisX->setRange(startDate, endDate);m_axisY->setRange(0, 100);// 设置y轴标签格式为整数m_axisY->setLabelFormat("%d");// 将Y轴分为四等份m_axisY->setTickCount(5);// 将X轴分为3等份m_axisX->setTickCount(4);m_chart->addSeries(addseries);addseries->attachAxis(m_axisX);addseries->attachAxis(m_axisY);}if(targetseries){m_chart->addSeries(targetseries);targetseries->attachAxis(m_axisX);targetseries->attachAxis(m_axisY);}
}void Widget::loadStyleSheet()
{QFile file(":/style.qss");if (file.open(QFile::ReadOnly)) {QTextStream stream(&file);QString styleSheet = stream.readAll();setStyleSheet(styleSheet);file.close();}
}
三、代码详情
CuiQingCheng/QtStudy - Gitee.comhttps://gitee.com/cuiqingcheng/QtStudy/tree/master/widget/demo/chartDemo