当前位置: 首页 > 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_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

相关文章:

Qt-QChart实现折线图

一、介绍场景 动态查看数据变化&#xff0c;或者了解数据发展趋势&#xff0c;让数据可以形象直观展现出来&#xff0c;这里推荐使用折线图的方式展现&#xff0c;本文抛砖引玉&#xff0c;简单实现一个实例&#xff0c;效果图如下&#xff1a; 二、实现步骤 1、charts组件 …...

取消Win10锁屏界面上显示的天气、市场和广告的操作

要取消Win10锁屏界面上显示的天气、市场和广告&#xff0c;您可以按照以下步骤操作&#xff1a; 方法一&#xff1a;更改锁屏界面设置 打开“设置”&#xff1a; 点击“开始”菜单&#xff0c;然后点击齿轮状的“设置”图标。 进入“个性化”&#xff1a; 在“设置”窗口中&a…...

IoT设备测试:从协议到硬件的全栈验证体系与实践指南

一、引言&#xff1a;IoT技术浪潮下的质量挑战 根据IDC预测&#xff0c;到2027年全球IoT设备数量将突破290亿台&#xff0c;涵盖智能家居、工业物联网&#xff08;IIoT&#xff09;、智慧城市、车联网等场景。然而&#xff0c;IoT系统的复杂性远超传统嵌入式设备——硬件异构性…...

大白话详细解读React框架的diffing算法

1. Diffing 算法是什么&#xff1f; Diffing 算法是 React 用来比较虚拟 DOM&#xff08;Virtual DOM&#xff09;树的一种算法。它的作用是找出前后两次渲染之间的差异&#xff08;diff&#xff09;&#xff0c;然后只更新这些差异部分&#xff0c;而不是重新渲染整个页面。 …...

自然语言处理入门

第一章 自然语言处理入门 1 什么是自然语言处理 【什么是人工智能&#xff0c;分别对应哪几个领域】 AI是模仿甚至超越人的某项机能&#xff0c;NLP、CV、ASR NLP是机器理解并生成人类语言2 自然语言处理的发展简史 1950 -- 图灵提出“机器能思考吗”&#xff0c;划时代性的…...

Arduino示例代码讲解:Pitch follower 跟随

Arduino示例代码讲解:Pitch follower 跟随 Pitch follower代码功能代码逐行解释1. 注释部分功能:硬件连接:2. `setup()` 函数3. `loop()` 函数硬件连接**扬声器连接**:**光敏电阻连接**:**Arduino板**:运行结果修改建议视频讲解Pitch follower 这段代码是一个Arduino示例…...

从TouchDriver Pro到Touchdriver G1,Weart触觉手套全系解析:XR交互的“真实触感”如何实现?

Weart旗下的Touchdriver Pro触觉手套和Touchdriver G1触觉手套&#xff0c;凭借其技术创新&#xff0c;为用户带来了全新的触觉体验。Touchdriver Pro触觉手套通过多模态触觉反馈技术&#xff0c;提供力反馈、纹理渲染和温度提示&#xff0c;让用户在虚拟环境中感受到真实的触觉…...

华为OD机试-阿里巴巴找黄金宝箱(I)-双指针(Java 2023 B卷 100分)

题目描述 阿里巴巴在去砍柴的路上发现了强盗集团的藏宝地,藏宝地有编号从 0 到 N 的箱子,每个箱子上贴有一个数字。黄金宝箱满足排在它之前的所有箱子数字和等于排在它之后的所有箱子数字和。第一个箱子左边部分的数字和定义为 0;最后一个宝箱右边部分的数字和定义为 0。请…...

ubuntu20如何升级nginx到最新版本(其它版本大概率也可以)

前言&#xff1a; Nginx非常常用&#xff0c;所以在网络安全方面备受“关注”。其漏洞非常多&#xff0c;要经常保持软件更新版本才能更好的保证安全。但是Ubuntu官网适配nginx非常慢&#xff0c;所以nginx官方也会推出针对主流Linux操作系统的包管理工具安装方式。 步骤&…...

排序算法实现:插入排序与希尔排序

目录 一、引言 二、代码整体结构 三、宏定义与头文件 四、插入排序函数&#xff08;Insertsort&#xff09; 函数作用 代码要点分析 五、希尔排序函数&#xff08;ShellSort&#xff09; 函数作用 代码要点分析 六、打印数组函数&#xff08;PrintSort&#x…...

UDP协议原理

UDP协议原理 本篇介绍 在前面使用UDP编程时已经基本了解了UDP的工作模式&#xff0c;也知道了UDP有三个特点&#xff1a; 无连接不可靠面向数据报 但是当时并没有具体谈论为什么UDP有以上三个特点&#xff0c;基于这个原因&#xff0c;本篇就会针对这三个原因进行介绍 UDP…...

EtherCAT转Modbus网关如何在倍福plc组态快速配置

EtherCAT转Modbus网关如何在倍福plc组态快速配置 在工业控制领域&#xff0c;EtherCAT和Modbus是两种常见的总线通信协议。EtherCAT以其高速的数据传输和灵活的网络配置被广泛应用于高性能自动化控制系统中&#xff0c;而Modbus则因其简单、稳定且兼容性强而被许多设备所支持。…...

如何设计大模型意图识别?

环境&#xff1a; 大模型 问题描述&#xff1a; 如何设计大模型意图识别&#xff1f; 解决方案&#xff1a; 1. 意图识别定义与核心任务 定义&#xff1a;意图识别&#xff08;Intent Recognition&#xff09;是从用户输入&#xff08;文本、语音等&#xff09;中解析其核…...

FPGA设计中时间单位科普

FPGA设计中时间单位主要有秒s&#xff0c;毫秒ms&#xff0c;微秒us&#xff0c;纳秒ns&#xff0c;皮秒ps&#xff0c; 使用秒s作为单位时一定要谨慎&#xff0c;因为秒s对于FPGA来说是一个很大的单位。FPGA的时钟周期通常是20ns左右&#xff0c;1秒意味着需要等待50000000个…...

DooTask在Linux的离线部署教程

DooTask在Linux的离线部署教程 下载安装包 从网盘中将安装包下载到本地&#xff0c;下载地址 通过网盘分享的文件&#xff1a;DooTask项目管理工具 链接: https://pan.baidu.com/s/1hGmLXonT4c8hLiDP1QBr8w?pwdgdp6 提取码: gdp6 通过网盘分享的文件&#xff1a;DooTask项目…...

Python实现WYY音乐下载

一、需求背景 WYY音乐作为国内主流音乐平台,其歌曲资源丰富但下载接口存在多重加密保护。本文将通过Python结合JS逆向技术,解析其核心加密逻辑,实现免费歌曲的下载功能。 二、技术难点分析 1. 接口加密机制 通过抓包分析可知,网易云核心接口使用两次加密: 第一次:获取…...

Java基础面试题学习

转换成自已的语言来回答&#xff0c;来源小林coding、沉默王二以及其它资源和自已改编。 1、概念 1、说一下Java的特点 我认为Java有很多特点 首先是平台无关性&#xff1a;Java可以实现一次编译到处运行&#xff0c;因为Java的编译器将源代码编译成字节码&#xff0c;使得该…...

【笔记】深度学习模型训练的 GPU 内存优化之旅:重计算篇

开设此专题&#xff0c;目的一是梳理文献&#xff0c;目的二是分享知识。因为笔者读研期间的研究方向是单卡上的显存优化&#xff0c;所以最初思考的专题名称是“显存突围&#xff1a;深度学习模型训练的 GPU 内存优化之旅”&#xff0c;英文缩写是 “MLSys_GPU_Memory_Opt”。…...

AI革命!蓝耘携手海螺AI视频,打造智能化视频新纪元

AI革命&#xff01;蓝耘携手海螺AI视频&#xff0c;打造智能化视频新纪元 前言 在这个信息爆炸的时代&#xff0c;视频已经成为我们获取信息、学习新知识的重要方式。而随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI与视频内容的结合为我们带来了全新的…...

Django+celery+flower

Djangoceleryflower Django的定时任务及可视化监控Django Django的定时任务及可视化监控 Django的定时任务&#xff0c;以及可视化监控。 Django Django&#xff1b; 首先在python中新建虚拟环境并激活 pip install virtualenv python -m venv venv source venv/bin/activa…...

MapReduce处理数据流程

&#xff08;一&#xff09;Shuffle MapReduce中的Shuffle过程指的是在Map方法执行后、Reduce方法执行前对数据进行分区排序的阶段 &#xff08;二&#xff09;处理流程 1. 首先MapReduce会将处理的数据集划分成多个split&#xff0c;split划分是逻辑上进行划分&#xff0c;…...

基于springboot的教务系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 这些年随着Internet的迅速发展&#xff0c;我们国家和世界都已经进入了互联网大数据时代&#xff0c;计算机网络已经成为了整个社会以及经济发展的巨大动能&#xff0c;各个高校的教务工作成为了学校管理事务的重要目标和任务&#xff0c;因此运用互联网技术来提高教务的…...

潮流霓虹酸性渐变液体流体扭曲颗粒边缘模糊JPG背景图片设计素材 Organic Textures Gradients Collection

这个系列将液体运动、霓虹灯和热浪扭曲提炼成一组有机纹理。渐变像水面上的油一样荡漾&#xff0c;模糊了科幻小说与自然之间的界限。这种未来主义的边缘&#xff0c;加上近乎生物的感觉&#xff0c;与正在进行的抽象数字超现实主义浪潮完美同步。 这套具有 20 种原始纹理和 20…...

现代时尚标签海报包装网站设计几何风PSAI无衬线英文字体安装包 Matahari Sans Font Family

Matahari&#xff08;英语&#xff1a;Sun&#xff09;是生命的动力源泉。与日常生活的其他部分协同作用的力量和能量的象征。这是我们人类需要的最基本的东西之一&#xff0c;就像交流一样。就像 Matahari 本身一样&#xff0c;文字的力量足以维持生计。 参考怪诞字体并受到埃…...

Spring MVC响应数据

handler方法分析 /*** TODO: 一个controller的方法是控制层的一个处理器,我们称为handler* TODO: handler需要使用RequestMapping/GetMapping系列,声明路径,在HandlerMapping中注册,供DS查找!* TODO: handler作用总结:* 1.接收请求参数(param,json,pathVariable,共享域等…...

jmeter验证正则表达式提取值是否正确

正则提取 验证提取是否正确...

共注意力机制及创新点深度解析

一、核心原理剖析 1. 基本思想 共注意力机制&#xff08;Co-Attention&#xff09;通过建立双向注意力交互通道&#xff0c;同步学习图像和问题两个模态的关键信息。与传统单向注意力相比&#xff0c;其核心创新在于&#xff1a; ​双向信息流&#xff1a;图像特征和问题特征…...

联想台式电脑启动项没有U盘

开机按F12&#xff0c;进入启动设备菜单&#xff0c;发现这里没有识别到插在主机的U盘&#xff1f; 解决方法 1、选上图的Enter Setup或者开机按F2&#xff0c;进入BIOS设置 选择Startup -> Primary Boot Sequence 2、选中“Excludeed from boot order”中U盘所在的一行 …...

基于 Python 爬取 TikTok 搜索数据 Tiktok爬虫(2025.3.17)

1. 前言 在数据分析和网络爬虫的应用场景中&#xff0c;我们经常需要获取社交媒体平台的数据&#xff0c;例如 TikTok。本篇文章介绍如何使用 Python 爬取 TikTok 用户搜索数据&#xff0c;并解析其返回的数据。 结果截图 2. 项目环境准备 在正式运行代码之前&#xff0c;我…...

【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解

【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解 &#xff08;图1-1&#xff09; 一、鸿蒙中App、HAP、HAR、HSP是什么&#xff1f; &#xff08;1&#xff09;App Pack&#xff08;Application Package&#xff09; 是应用发布的形态&#xff0c;上架应用市场是以App Pa…...