Qt編寫自定義控件60-聲音波形圖

1、前言

這個控件源自於一個音樂播放器,在寫該音樂播放器的時候,須要將音頻的數據轉換成對應的頻譜顯示,採用的fmod第三方庫來處理(fmod聲音系統是爲遊戲開發者準備的革命性音頻引擎,很是強大和牛逼),fmod負責拿到音頻數據對應的採樣頻譜數據,而後傳給這個控件進行繪製便可,本控件主須要專一於繪製便可,這樣fmod對應封裝的類專一於音頻採集等處理,實現了隔離,修改和增長功能比較方便,聲音波形圖控件除了能夠設置採樣的深度之外,還支持三種數據樣式展現,線條樣式、柱狀樣式、平滑樣式。爲了能夠直接定位到某一位置直接跳轉到音頻位置,還增長了繪製數線條定位線。linux

2、實現的功能

  • 1:可設置採樣深度
  • 2:可設置當前位置線條寬度/線條顏色
  • 3:可設置前景色/背景色
  • 4:可設置數據展現樣式,線條樣式/柱狀樣式/平滑樣式

3、效果圖

4、頭文件代碼

#ifndef WAVEDATA_H
#define WAVEDATA_H

/**
 * 音量採樣值波形控件 做者:feiyangqingyun(QQ:517216493) 2017-9-10
 * 1:可設置採樣深度
 * 2:可設置當前位置線條寬度/線條顏色
 * 3:可設置前景色/背景色
 * 4:可設置數據展現樣式,線條樣式/柱狀樣式/平滑樣式
 */

#include <QWidget>

#ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif

class QDESIGNER_WIDGET_EXPORT WaveData : public QWidget
#else
class WaveData : public QWidget
#endif

{
    Q_OBJECT
    Q_ENUMS(WaveStyle)
    Q_PROPERTY(double deep READ getDeep WRITE setDeep)
    Q_PROPERTY(bool showLine READ getShowLine WRITE setShowLine)
    Q_PROPERTY(int lineWidth READ getLineWidth WRITE setLineWidth)
    Q_PROPERTY(QColor lineColor READ getLineColor WRITE setLineColor)
    Q_PROPERTY(QColor foreground READ getForeground WRITE setForeground)
    Q_PROPERTY(QColor background READ getBackground WRITE setBackground)
    Q_PROPERTY(WaveStyle waveStyle READ getWaveStyle WRITE setWaveStyle)

public:
    enum WaveStyle {
        WaveStyle_Line = 0,     //線條樣式
        WaveStyle_Smooth = 1,   //平滑樣式
        WaveStyle_Bar = 2       //柱狀樣式
    };

    explicit WaveData(QWidget *parent = 0);

protected:
    void mousePressEvent(QMouseEvent *);
    void paintEvent(QPaintEvent *);
    void drawBg(QPainter *painter);
    void drawData(QPainter *painter);
    void drawLine(QPainter *painter);

private:    
    double deep;                //採集深度
    bool showLine;              //顯示線條
    int lineWidth;              //線條寬度
    QColor lineColor;           //線條顏色
    QColor foreground;          //前景色
    QColor background;          //背景色
    WaveStyle waveStyle;        //數據樣式

    int length;                 //採樣點長度
    int position;               //當前位置
    QVector<float> data;        //採樣點數據

public:    
    double getDeep()            const;
    bool getShowLine()          const;
    int getLineWidth()          const;
    QColor getLineColor()       const;
    QColor getForeground()      const;
    QColor getBackground()      const;
    WaveStyle getWaveStyle()    const;

    QSize sizeHint()            const;
    QSize minimumSizeHint()     const;

public slots:
    //設置深度
    void setDeep(double deep);

    //設置是否顯示線條
    void setShowLine(bool showLine);
    //設置線條寬度
    void setLineWidth(int lineWidth);
    //設置線條顏色
    void setLineColor(const QColor &lineColor);

    //設置前景色
    void setForeground(const QColor &foreground);
    //設置背景色
    void setBackground(const QColor &background);

    //設置數據樣式
    void setWaveStyle(const WaveStyle &waveStyle);

    //設置總長度
    void setLength(int length);
    //設置當前位置
    void setPosition(int position);

    //設置當前數據
    void setData(const QVector<float> &data);
    //清空數據
    void clearData();

signals:
    void positionChanged(int position);
};

#endif // WAVEDATA_H

5、核心代碼

void WaveData::paintEvent(QPaintEvent *)
{
    //繪製準備工做,啓用反鋸齒
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);

    //繪製背景
    drawBg(&painter);
    //繪製數據
    drawData(&painter);
    //繪製當前位置線條
    drawLine(&painter);
}

void WaveData::drawBg(QPainter *painter)
{
    painter->save();
    painter->fillRect(this->rect(), background);
    painter->restore();
}

void WaveData::drawData(QPainter *painter)
{
    if (data.count() == 0) {
        return;
    }

    painter->save();

    //獲取最大值最小值
    float max = data.at(0);
    float min = data.at(0);
    int count = data.count();

    for (int i = 1; i < count; i++) {
        if (max < data.at(i)) {
            max = data.at(i);
        }

        if (min > data.at(i)) {
            min = data.at(i);
        }
    }

    //轉化成當前屏幕的內的座標大小
    max += deep;
    min -= deep;

    //自動轉換數據到屏幕座標位置
    QVector<QPointF> points;
    for (int i = 0; i < count; i++) {
        double x = i * width() / count;
        double y = height() - (((data.at(i) - min) / (max - min)) * height());
        points.append(QPointF(x, y));
    }

    //繪製不一樣的風格
    if (waveStyle == WaveStyle_Line) {
        painter->setPen(foreground);
        for (int i = 0; i < count - 1; i++) {
            painter->drawLine(points.at(i), points.at(i + 1));
        }
    } else if (waveStyle == WaveStyle_Smooth) {
        painter->setPen(foreground);
        QPainterPath path = SmoothCurveCreator::createSmoothCurve(points);
        painter->drawPath(path);
    } else if (waveStyle == WaveStyle_Bar) {
        double penWidth = width() / (count * 1.6);
        QPen pen;
        pen.setColor(foreground);
        pen.setWidthF(penWidth);
        pen.setCapStyle(Qt::RoundCap);
        painter->setPen(pen);

        for (int i = 0; i < count; i++) {
            QPointF point = points.at(i);
            double x = point.x() + penWidth / 1.2;
            painter->drawLine(QPointF(x, point.y()), QPointF(x, height()));
        }
    }

    painter->restore();
}

void WaveData::drawLine(QPainter *painter)
{
    if (!showLine || position > length || data.count() <= 0) {
        return;
    }

    painter->save();

    QPen pen;
    pen.setWidth(lineWidth);
    pen.setColor(lineColor);
    painter->setPen(pen);

    //計算當前位置對應的座標
    int x = ((double)position / length) * width();
    painter->drawLine(x, 0, x, height());

    painter->restore();
}

6、控件介紹

  1. 超過150個精美控件,涵蓋了各類儀表盤、進度條、進度球、指南針、曲線圖、標尺、溫度計、導航條、導航欄,flatui、高亮按鈕、滑動選擇器、農曆等。遠超qwt集成的控件數量。
  2. 每一個類均可以獨立成一個單獨的控件,零耦合,每一個控件一個頭文件和一個實現文件,不依賴其餘文件,方便單個控件以源碼形式集成到項目中,較少代碼量。qwt的控件類環環相扣,高度耦合,想要使用其中一個控件,必須包含全部的代碼。
  3. 所有純Qt編寫,QWidget+QPainter繪製,支持Qt4.6到Qt5.13的任何Qt版本,支持mingw、msvc、gcc等編譯器,支持任意操做系統好比windows+linux+mac+嵌入式linux等,不亂碼,可直接集成到Qt Creator中,和自帶的控件同樣使用,大部分效果只要設置幾個屬性便可,極爲方便。
  4. 每一個控件都有一個對應的單獨的包含該控件源碼的DEMO,方便參考使用。同時還提供一個全部控件使用的集成的DEMO。
  5. 每一個控件的源代碼都有詳細中文註釋,都按照統一設計規範編寫,方便學習自定義控件的編寫。
  6. 每一個控件默認配色和demo對應的配色都很是精美。
  7. 超過130個可見控件,6個不可見控件。
  8. 部分控件提供多種樣式風格選擇,多種指示器樣式選擇。
  9. 全部控件自適應窗體拉伸變化。
  10. 集成自定義控件屬性設計器,支持拖曳設計,所見即所得,支持導入導出xml格式。
  11. 自帶activex控件demo,全部控件能夠直接運行在ie瀏覽器中。
  12. 集成fontawesome圖形字體+阿里巴巴iconfont收藏的幾百個圖形字體,享受圖形字體帶來的樂趣。
  13. 全部控件最後生成一個動態庫文件(dll或者so等),能夠直接集成到qtcreator中拖曳設計使用。
  14. 目前已經有qml版本,後期會考慮出pyqt版本,若是用戶需求量很大的話。
  15. 自定義控件插件開放動態庫使用(永久免費),無任何後門和限制,請放心使用。
  16. 目前已提供26個版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
  17. 不按期增長控件和完善控件,不按期更新SDK,歡迎各位提出建議,謝謝!
  18. Qt入門書籍推薦霍亞飛的《Qt Creator快速入門》《Qt5編程入門》,Qt進階書籍推薦官方的《C++ GUI Qt4編程》。
  19. 強烈推薦程序員自我修養和規劃系列書《大話程序員》《程序員的成長課》《解憂程序員》,受益不淺,受益終生!
  20. SDK下載連接:https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取碼:877p
相關文章
相關標籤/搜索