当前位置: 首页 > article >正文

Qt-QChart实现折线图

一、介绍场景

动态查看数据变化,或者了解数据发展趋势,让数据可以形象直观展现出来,这里推荐使用折线图的方式展现,本文抛砖引玉,简单实现一个实例,效果图如下:

二、实现步骤

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_NAMESPACE

class colorForm;

// 使用 QChart,必须包含这个名字空间,不然,就要加名字空间
// 例如:QtCharts::QChart
QT_CHARTS_USE_NAMESPACE

typedef 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_OBJECT

public:
    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 轴文本颜色为红色,字体大小为 12
    QFont 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 轴文本颜色,字体大小为 12
    QFont 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对象,用于显示QChart
    m_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


http://www.kler.cn/a/590408.html

相关文章:

  • [贪心算法]-最大数(lambda 表达式的补充)
  • Java 集合框架(Collection)
  • QT:动态属性和对象树
  • Compose笔记(九)--Checkbox
  • [数据结构]排序之 快速排序详解(递归版非递归版)
  • 游戏引擎学习第162天
  • 2025年高职大数据可视化实训室建设及实训平台整体解决方案
  • Vue秘籍:如何动态修改页面 Title(浏览器页签名称)?
  • idea cpu干到100%的解决方法?
  • HarmonyOS NEXT开发实战——HUAWEI DevEco Studio 开发指南
  • 车载以太网测试-13【网络层-IGMP协议】
  • 【Godot】Viewpoint
  • mapbox基础,使用线类型geojson加载symbol符号图层,用于标注文字
  • 解锁智慧养老新可能,全面提升养老生活质量
  • Go语言中的错误处理与异常恢复:性能对比与实践思考
  • 【leetcode】51.N皇后
  • 如何检查CMS建站系统的插件是否安全?
  • 《灵珠觉醒:从零到算法金仙的C++修炼》卷三·天劫试炼(60)五火七禽扇灭火 - 接雨水(双指针与动态规划)
  • Kubernetes Network Policy使用场景
  • 微软远程桌面即将下架?Splashtop:更稳、更快、更安全的 RDP 替代方案