QCustomPlot绘图类详解(大白话)

2023-09-14 20:17:36

本文假定你会使用Qt开发,但未接触过QCustomPlot绘图类或者是刚接触。

如何往Qt中引入QCustomPlot

  1. 首先,去官网下载最新版本的源码,注意是QCustomPlot.tar.gz这个文件,里面包含源码和示例。实际上,我们只需要qcustomplot.hqcustomplot.h这两个源文件。
    官网下载
  2. 将代码文件拷贝到本地工程,并引入。
    引入源文件
    QCustomPlot需要依赖printsupport模块,如果你是使用QT+VS开发,配置如下:
    Qt+Vs
    如果是Qt Create开发,在.pro文件中添加:QT += QWidget printsupport
  3. 在Qt中新建ui文件,拖拽一个QWidget控件,将其提升为QCustomPlot
    在这里插入图片描述

QCustomPlot常用函数

// 设置背景色
ui.plotWidget->setBackground(QBrush(QColor("#404040")));

// 设置X/Y轴的标签
ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));

// 设置X/Y轴标签字体
ui.plotWidget->xAxis->setLabelFont(plotFont);

// 设置X/Y轴标签颜色
ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));

// 设置x=0或y=0所在直线的画笔
ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));

// 设置X/Y轴刻度范围
ui.plotWidget->xAxis->setRange(1, PT_CNT);

// 设置X/Y轴刻度数,也就是分为几段
ui.plotWidget->xAxis->ticker()->setTickCount(8);

// 设置X/Y轴刻度值文本的颜色
ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));

// 设置X/Y轴轴线的画笔
ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));

// 设置X/Y轴大刻度的画笔,被分段的位置
ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));

// 设置X/Y轴小刻度的画笔
ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));

// 设置内部网格线的画笔
ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));

// 添加一个图层
ui.plotWidget->addGraph();

// 为对应图层添加数据
ui.plotWidget->graph(0)->addData(keys, values);

// 为图层设置画笔
ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));

// 设置是/否抗锯齿
ui.plotWidget->graph(0)->setAntialiasedFill(true);

// 刷新绘图,更改数据后需手动刷新(缩放会自动刷新)
ui.plotWidget->replot();

// 支持拖拽和缩放
ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

绘制直方图

更改QCustomPlot相关属性,这里以颜色修改为主(稍有点乱哈),创建距离-测距次数的直方图。
在这里插入图片描述
相关代码如下:

void PlotTest::InitForm()
{
    ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

    ui.plotWidget->setBackground(QBrush(QColor("#404040")));
    ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));
    ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));

    QFont plotFont = font();
    plotFont.setPointSizeF(10.0);

    ui.plotWidget->xAxis->setLabelFont(plotFont);
    ui.plotWidget->yAxis->setLabelFont(plotFont);
    ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->yAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->yAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->yAxis->setRange(-10, 90);
    ui.plotWidget->xAxis->ticker()->setTickCount(8);
    ui.plotWidget->yAxis->ticker()->setTickCount(8);
    ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->yAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->yAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->yAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->yAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));
    ui.plotWidget->yAxis->grid()->setPen(QPen(QColor(Qt::darkGreen), 1, Qt::DotLine));

    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 - 10);
    }
    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
}

刷新直方图

刷新直方图比较简单,刷新指定图层的数据即可。有2种方式:

  • 更换数据
ui.plotWidget->graph(0)->data()->clear(); // 清楚图层对应的数据
ui.plotWidget->graph(0)->addData(keys, values); // 添加新的数据
  • 更换图层
ui.plotWidget->clearGraphs(); // 删除图层(单个或所有)
ui.plotWidget->addGraph(); // 新建图层
ui.plotWidget->graph(0)->addData(keys, values); // 添加新数据

注:两种方式会适用于不同的场景下。
请添加图片描述

绘制连续的直方图

连续直方图可以理解为:不断往图层里添加数据。需要注意的是,每次添加数据都需要更新刻度范围。代码如下:

void PlotTest::DrawContinueGraph()
{
    QVector<double> keys, values;

    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(mRefreshCnt * PT_CNT + i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->xAxis->setRange(1, PT_CNT * (mRefreshCnt + 1));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();

    mRefreshCnt++;
}

请添加图片描述

完整代码

// PlotTest.h文件
#pragma once

#include <QtWidgets/QWidget>
#include "ui_PlotTest.h"

class PlotTest : public QWidget
{
    Q_OBJECT

public:
    PlotTest(QWidget *parent = nullptr);
    ~PlotTest();

public:
    void InitForm();            // 初始化控件
    void DrawStaticGraph();     // 绘制静态库
    void DrawDynamicGraph();    // 绘制动态库(单图刷新)
    void DrawContinueGraph();   // 绘制连续图(多图刷新)
    
public slots:
    void on_btnDynamicDraw_clicked();
    void on_btnContinueDraw_clicked();

private:
    Ui::PlotTestClass ui;
    int mRefreshCnt; // 连续刷新次数
};
// PlotTest.cpp文件
#include "PlotTest.h"
#include "CustomPlot\qcustomplot.h"

#define PT_CNT       200    // 点数
#define GRAPH_CNT    5      // 图数

PlotTest::PlotTest(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    InitForm();
    mRefreshCnt = 1;
}

PlotTest::~PlotTest()
{

}

void PlotTest::on_btnDynamicDraw_clicked()
{
    ui.btnDynamicDraw->setEnabled(false);
    ui.btnContinueDraw->setEnabled(false);
    mRefreshCnt = 1;

    for (int i = 0; i < 10; i++)
    {
        DrawDynamicGraph();
        Sleep(500);
    }

    ui.btnDynamicDraw->setEnabled(true);
    ui.btnContinueDraw->setEnabled(true);
}

void PlotTest::on_btnContinueDraw_clicked()
{
    ui.btnDynamicDraw->setEnabled(false);
    ui.btnContinueDraw->setEnabled(false);
    mRefreshCnt = 0;
    ui.plotWidget->graph(0)->data()->clear();
    ui.plotWidget->xAxis->setRange(1, PT_CNT);

    for (int i = 0; i < 10; i++)
    {
        DrawContinueGraph();
        Sleep(500);
    }

    ui.btnDynamicDraw->setEnabled(true);
    ui.btnContinueDraw->setEnabled(true);
}

void PlotTest::InitForm()
{
    ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

#if 0
    ui.plotWidget->setBackground(QBrush(QColor("#404040")));
    ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));
    ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));

    QFont plotFont = font();
    plotFont.setPointSizeF(10.0);

    ui.plotWidget->xAxis->setLabelFont(plotFont);
    ui.plotWidget->yAxis->setLabelFont(plotFont);
    ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->yAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->yAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->yAxis->setRange(-10, 90);
    ui.plotWidget->xAxis->ticker()->setTickCount(8);
    ui.plotWidget->yAxis->ticker()->setTickCount(8);
    ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->yAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->yAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->yAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->yAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));
    ui.plotWidget->yAxis->grid()->setPen(QPen(QColor(Qt::darkGreen), 1, Qt::DotLine));

    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 - 10);
    }
    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
#else
    ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));
    ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->yAxis->setRange(1, 100);
    ui.plotWidget->xAxis->ticker()->setTickCount(8);
    ui.plotWidget->yAxis->ticker()->setTickCount(8);

    DrawStaticGraph();

#endif
}

void PlotTest::DrawStaticGraph()
{
    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
}

void PlotTest::DrawDynamicGraph()
{
    ui.plotWidget->clearGraphs();
    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
}

void PlotTest::DrawContinueGraph()
{
    QVector<double> keys, values;

    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(mRefreshCnt * PT_CNT + i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->xAxis->setRange(1, PT_CNT * (mRefreshCnt + 1));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();

    mRefreshCnt++;
}
更多推荐

Learn Prompt-基础用法

基本法则​相比于搜索引擎,ChatGPT的优势在于其高效的想法关联和信息归纳能力。在进一步讲解提示的构建思路前,我希望你可以了解到两点通用的经验法则,用来提高生成AI模型的输出质量。其中包括尝试提示的多种表述以获得最佳结果使用清晰简短的提示,避免不必要的词语减少不精确的描述当然,这并不是所有的经验法则。我们希望的是,你

Qt浏览器模块的几点说明

Qt5.6以前用的是webkit,Qt5.6版本以后分两种情况,一种是mingw编译器(windows系统)对应的Qt库不再提供浏览器模块。Qt5.6以后的版本在linux系统和mac等系统,都不存在没有浏览器控件的情况,都使用的是webengine。仅仅是windows上的mingw编译器的Qt版本没有,其他系统其实

【线性回归、岭回归、Lasso回归分别预测患者糖尿病病情】数据挖掘实验一

Ⅰ、项目任务要求任务描述:将“diabetes”糖尿病患者数据集划分为训练集和测试集,利用训练集分别结合线性回归、岭回归、Lasso回归建立预测模型,再利用测试集来预测糖尿病患者病情并验证预测模型的拟合能力。具体任务要求如下:搜集并加载“diabetes”患者糖尿病指数数据集。定义训练集和测试集(训练集和测试集比例分别

并发编程系列-AQS

AbstractQueuedSynchronizer(AQS)是一个抽象队列同步器,它用于构建依赖于先进先出(FIFO)等待队列的阻塞锁和相关同步器的框架。该类的目的在于提供基本功能的封装,适用于大多数需要使用单个原子int值表示同步状态的同步器。举例来说,ReentrantLock、Semaphore以及Future

《计算机视觉中的多视图几何》笔记(3)

3ProjectiveGeometryandTransformationsof3D这章主要讲的是3D的射影几何,与2D的射影几何差不多。主要区别是:3D射影几何对偶的是点和平面,直线是自对偶的。3D空间中直线有4个自由度,这一现象并不是那么容易直接得出。一种方法是把直线用正交平面两个交点表示。文章目录3Projecti

【Rust 基础篇】Rust 父trait:扩展和组织trait的继承体系

导言Rust是一种以安全性和高效性著称的系统级编程语言,其设计哲学是在不损失性能的前提下,保障代码的内存安全和线程安全。在Rust中,trait是一种用于抽象类型行为的机制。有时候,我们需要在一个trait的基础上扩展更多的行为,或者将多个trait组合起来形成一个更大的trait继承体系。这时,Rust的父trait

vue3 - 前端 Vue 项目提交GitHub 使用Actions自动化部署

GitHubDemo地址在线预览参考文章使用GithubActions发布Vue网站到GithubPage使用GithubActions将Vue项目部署到GithubPages前端使用githubpages部署自己的网站GitHubActions自动化部署前端项目指南前言vue前端项目写好之后,想部署到线上通过在线地址

助力经销商打赢旺季攻坚战,全兴在全国范围内拉开“兴风暴”

执笔|姜姜编辑|萧萧中秋、国庆历来是白酒消费的旺季,也是完成当年任务的关键期,尤其今年“双节”合一,各大食品饮料企业都憋足了劲,白酒促销大戏也轮番上演。作为中国“老八大名酒”之一的全兴酒业谋定而动,以积极奔跑的姿态,不断精耕重点区域地级市场,紧抓双节动销,助力渠道伙伴在白酒旺销季打一场大胜仗。对话金牌酒商,老名酒筑牢大

终于还是熬不住了,转行了,分享一波刚学到的知识吧,字符串的自带函数.py

网传IT行业很难,没错我是真真正正的体验到了(😭)大家好,我原来是在大学自学了java的大部分技术,基本上可以达到企业级开发了,大三一结束我就在浙江杭州开始找工作,找了两个月,中间一共找到过三个关于后端开发的工作,加在一起工作了半个月左右,种种原因都没有继续工作。后来面试了一个Python爬虫做rpa自动化的实习生,

华为云CodeArts Check代码检查服务用户声音反馈集锦(6)

CodeArtsCheck(原CodeCheck),是自主研发的代码检查服务。建立在华为30年自动化源代码静态检查技术积累与企业级应用经验的沉淀之上,为用户提供代码风格、通用质量与网络安全风险等丰富的检查能力,提供全面质量报告、便捷的问题闭环处理帮助企业有效管控代码质量,助力企业成功:感兴趣的小伙伴可以点此>>体验下服

马斯洛需求层次模型分析之云安全浅谈

基于马斯洛需求层次模型,我们可以将互联网云安全建设和运营分析分为五个阶段,每个阶段对应一些关键的安全关键词,以下内容是对这些阶段的浅显分析:第一阶段:基础设施安全(生理需求)在初始阶段,云服务提供商需要确保基础设施的安全性,包括数据中心、网络、系统等方面。这涉及到的关键词有:数据中心安全:确保数据中心物理设施的安全,如

热文推荐