-
音频波形可视化:该控件用于将音频样本数据可视化为波形,常用于音频处理软件中以展示音频信号的时间域特性。
-
动态数据绘制:控件能够响应外部数据的变化并重新绘制波形,适用于实时或动态的音频数据流。
-
自定义绘制逻辑:通过Qt的绘图API,特别是
QPainter
和QPainterPath
,实现了波形的自定义绘制,包括线条的平滑、颜色渐变以及路径的描绘。 -
性能优化:通过双缓冲技术(使用
QPixmap
)和适当的数据处理,减少了绘制过程中的计算量,提高了渲染效率。 -
颜色编码:使用颜色渐变来区分波形的不同振幅区域,比如使用红色到蓝色的渐变表示波形的高低振幅,绿色表示零点线,使得波形的阅读更直观。
-
可扩展性:控件为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(); }