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

5 篇文章 0 订阅

  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_OBJECT
    
    public:
        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();
    }

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Qt/C++是一种开发桌面应用程序的跨平台开发框架,它提供了丰富的工具和类库,能够方便快捷地编写自定义控件源码。 首先,我们需要创建一个继承自QWidget或QFrame的类来实现自定义控件。在这个类中,我们可以重载一些事件处理函数来实现控件的特定功能,比如绘制事件函数paintEvent()、鼠标事件函数mousePressEvent()等等。通过这些函数,我们可以控制控件的外观、响应用户输入等。 在实现自定义控件的外观时,可以利用Qt提供的各种绘图工具和API。例如,可以使用QPainter类来绘制各种形状、图像、文字等,还可以使用QPen和QBrush类来设置绘制的样式和颜色。通过这些工具,我们可以实现各种个性化的外观效果,如圆角、渐变、阴影等。 对于自定义控件的功能实现,可以根据需求使用Qt提供的各种功能模块。比如,使用QTimer类实现定时器功能,使用QMediaPlayer类实现音视频播放功能等等。此外,Qt还提供了一系列的信号和槽机制,可以方便地实现控件之间的交互和通信。 在自定义控件的使用方面,可以通过在其他QWidget中使用该控件的对象的方式来使用它。将自定义控件放入项目中,然后在界面中添加该控件的实例对象,即可展示该控件,并与其交互。也可以通过在UI界面设计软件中将该控件拖拽到需要的位置上,然后使用信号槽机制来实现与其他控件的交互。 总之,Qt/C++编写自定义控件源码需要熟悉Qt的基本概念和API,并结合自身的需求来设计和实现控件的外观和功能。通过合理的设计和编码,可以创建出各种各样的自定义控件,丰富应用程序的界面和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

(机)(器)(视)(觉)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值