Qt/C++ 波形绘制双缓冲下改善PaintEvent连续绘制卡顿问题(完整代码解析)

本文主要是介绍Qt/C++ 波形绘制双缓冲下改善PaintEvent连续绘制卡顿问题(完整代码解析),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  1. 音频波形可视化:该控件用于将音频样本数据可视化为波形,常用于音频处理软件中以展示音频信号的时间域特性。

  2. 动态数据绘制:控件能够响应外部数据的变化并重新绘制波形,适用于实时或动态的音频数据流。

  3. 自定义绘制逻辑:通过Qt的绘图API,特别是QPainterQPainterPath,实现了波形的自定义绘制,包括线条的平滑、颜色渐变以及路径的描绘。

  4. 性能优化:通过双缓冲技术(使用QPixmap)和适当的数据处理,减少了绘制过程中的计算量,提高了渲染效率。

  5. 颜色编码:使用颜色渐变来区分波形的不同振幅区域,比如使用红色到蓝色的渐变表示波形的高低振幅,绿色表示零点线,使得波形的阅读更直观。

  6. 可扩展性:控件为Qt框架下的自定义控件,可以很容易地集成到更大的Qt应用程序中,并根据需求进行定制和扩展。

    
    #ifndef WAVEFORMWIDGET_H
    #define WAVEFORMWIDGET_H#include <QWidget>
    #include <QPixmap>class WaveformWidget : public QWidget {Q_OBJECTpublic:explicit WaveformWidget(QWidget *parent = nullptr);~WaveformWidget();void setSamples(const QList<float> &newSamples);protected:void paintEvent(QPaintEvent *event) override;void resizeEvent(QResizeEvent *event) override;private:QList<float> samples; // 用于存储音频样本的列表QPixmap buffer; // 双缓冲的画布void redrawBuffer(); // 在画布上重新绘制波形
    };#endif // WAVEFORMWIDGET_H
    #include "WaveformWidget.h"
    #include <QPainter>
    #include <QResizeEvent>WaveformWidget::WaveformWidget(QWidget *parent): QWidget(parent) {// 初始化双缓冲画布buffer = QPixmap(size());buffer.fill(Qt::black);
    }WaveformWidget::~WaveformWidget() {
    }void WaveformWidget::setSamples(const QList<float> &newSamples) {samples = newSamples;redrawBuffer(); // 更新画布
    }void WaveformWidget::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.drawPixmap(0, 0, buffer);
    }void WaveformWidget::resizeEvent(QResizeEvent *event) {// 调整画布大小并重新绘制buffer = QPixmap(event->size());buffer.fill(Qt::black);redrawBuffer();
    }void WaveformWidget::redrawBuffer() {// 确保画布准备好if (buffer.size() != size()) {buffer = QPixmap(size());}QPainter painter(&buffer);painter.setRenderHint(QPainter::Antialiasing);// 重置画布背景buffer.fill(Qt::black);if (samples.isEmpty()) return;const int middleY = buffer.height() / 2;const int upperLimit = middleY / 2;  // -50 to 50 对应的 Y 坐标const int lowerLimit = middleY + upperLimit;// 创建路径和描边路径QPainterPath path, strokePath;path.moveTo(0, middleY);qreal xStep = static_cast<qreal>(buffer.width()) / (samples.size() - 1);// 根据样本数据构造波形路径for (int i = 0; i < samples.size(); ++i) {qreal x = i * xStep;qreal y = middleY - (samples.at(i) * middleY / 100.0);path.lineTo(x, y);strokePath.lineTo(x, y);}// 绘制渐变QLinearGradient gradient(0, 0, 0, buffer.height());gradient.setColorAt(0.0, QColor(255, 0, 0));    // 顶部为红色gradient.setColorAt(0.25, QColor(0, 0, 255));   // 中部为蓝色gradient.setColorAt(0.5, Qt::transparent);      // 中间透明gradient.setColorAt(0.75, QColor(0, 0, 255));   // 中部为蓝色gradient.setColorAt(1.0, QColor(255, 0, 0));    // 底部为红色QPen pen(gradient, 2);painter.setPen(pen);painter.drawPath(strokePath);// 绘制中间的零点线QPen centerLinePen(Qt::green);centerLinePen.setWidth(1);painter.setPen(centerLinePen);painter.drawLine(0, middleY, buffer.width(), middleY);// 请求更新控件update();
    }

这篇关于Qt/C++ 波形绘制双缓冲下改善PaintEvent连续绘制卡顿问题(完整代码解析)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/942778

相关文章

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu