基于Qt的音乐播放器制作

基于Qt的音乐播放器制作

使用浏览器自带工具抓包歌曲资源

开发人员工具抓包

点击浏览器右上角的 “…” 快捷键(Alt + F);
在这里插入图片描述
点击其中的“更多工具” ➡ “开发人员工具”;
打开开发人员工具出现以下界面:
在这里插入图片描述
选中网络 ➡ 禁用缓存,并点击清除清空网络活动记录;
打开一个音乐搜索引擎(如酷狗、网易音乐、小众音乐平台网址);
ps:大平台网络加密严密且收费歌曲偏多,抓包失败可能性偏大
这里我选用的是一个小众搜索引擎:
https://l-by.cn/yinyue/
打开音乐搜索引擎和开发人员工具,搜索引擎搜索一个歌手,并点击播放该歌手的一首歌(若已经在搜索后的歌曲界面则刷新页面);
ps:每次搜索播放歌曲或刷新时要先清除开发人员工具,以便清理多余的网络活动记录更好的找到音乐资源包
在这里插入图片描述
如上图所示抓包到这三个 xhr 类型的文件,分别点击文件并选择标头、负载和预览查看
在这里插入图片描述
以url包为例,包头显示的请求方式为POST,连接类型为application/x-www-form-urlencoded; charset=UTF-8,负载中可查看源(types=url&id=1978137630&source=netease)为音乐播放资源包(url),id(每一个id对应一首歌的播放源以及歌词源)以及 source (音乐播放来源,netease为网易云);预览中则为对应歌曲的mp3格式播放网址;
ps:url(歌曲播放)与lyric(歌曲歌词)的id号相同,pic(歌曲专辑图)的id号与前两者不同

接口测试

为了更加直观的查看一首歌的各类信息,便于搜索查找想听的歌曲,我们对刚刚抓到的网络端口进行接口测试;
使用网站:https://getman.cn/
采用POST请求方式连接音乐搜索网址(网址末尾需加上/api.php),填入相应的包头连接类型,body填入查看源的数据:
在这里插入图片描述
在这里插入图片描述
body中填入
types=search&count=30&source=netease&pages=1&name=“许嵩”
点击√便可以查看歌单信息列表:
在这里插入图片描述
body中填入
types=url&id=1978137630&source=netease
便可以查看单首歌的播放网址、歌词和歌曲专辑:
在这里插入图片描述
查询 lyric 和 pic 的方式相同。

程序编写整体思路

制作流程

先创建一个 Qt Widgets Application(桌面Qt应用):MusicInterface
在 main.cpp 文件中调用打开 MusicInterface类(ui界面),由该类关联三个新创建的类: HttpHandle(http协议网络通信、数据解析类)、MusicPlayer (音乐播放、歌词解析类)、GraphicsView(专辑图片处理类);
其中的 GraphicsView 类又关联了两个新创建的类:DiskItem(光盘图元旋转类)、NeedleItem(唱针图元摆动类),最后创建一个新类:AboutInterface(关于界面窗口)依附于主窗口界面类中;
在主窗口界面上添加控件来满足音乐播放器相应的功能:
graphicsView 插入专辑图、特效动图
pushButton_playOrder 随机、顺序播放
pushButton_play 播放暂停
pushButton_lastSong 上一首
pushButton_nextSong 下一首
verticalSlider_volume 音量调节
horizontalSlider_progressBar 播放进度条
label_startTime 开始时间
label_endTime 结束时间
lineEdit_search 搜索歌单
tabWidget 在线音乐、本地音乐存放容器
tableWidget_musicList 存放歌曲列表
textEdit_lyric 存放歌曲歌词

思维框架图

在这里插入图片描述

使用Qt对歌曲资源包解析(http协议)

POST连接音源网址

创建一个HPPT协议连接的类继承QObject:生成 HttpHandle.h 和 HttpHandle.cpp 文件
在该类中声明并实现一个公有的歌源连接函数:

QByteArray HttpHandle::postSearch(const QString &body)
{
    QNetworkRequest networkRequest(QUrl("https://l-by.cn/yinyue/api.php"));
    networkRequest.setRawHeader(QByteArray("content-type"), QByteArray("application/x-www-form-urlencoded; charset=UTF-8"));
    QEventLoop eventLoop;
    QNetworkReply *networkReply = networkAccessManager->post(networkRequest, body.toUtf8());
    connect(networkReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    return networkReply->readAll();
}

该函数需要绑定音乐搜索引擎网址以及包头里的连接类型,然后采用POST的方式连接接口;

使用QtJSON解析歌单数据

在HttpHandle类中声明并实现一个解析歌单数据函数:

void HttpHandle::searchMusicList(const QString &searchData)
{
    QString body = QString("types=search&count=30&source=netease&pages=1&name=%1").arg(searchData);//30是一面歌曲数,1是页面数,可以用%2添加参数进行翻页,后面加上.arg(int)
    QByteArray musicData = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析音乐列表JSON数据失败!错误码:" << error.errorString();
        return;
    }

    QJsonArray musicInfoArray = JsonDocument.array();
    for (int i = 0; i < musicInfoArray.size(); ++i) {
        QJsonObject musicObject = musicInfoArray[i].toObject();
        QStringList musicInfo;
        QString id = QString::number(musicObject["id"].toInt());
        QString picId = musicObject["pic_id"].toString();
        QString name = musicObject["name"].toString();

        QJsonArray artistArray = musicObject["artist"].toArray();
        QString artist;
        for (int j = 0; j < artistArray.size(); ++j) {
            artist = artist + artistArray[j].toString() + ',';
        }
        artist.chop(1); //删除最后一个多余的','
        QString album = musicObject["album"].toString();
        musicInfo << id << picId << name << artist << album;
        emit signalShowMusicInfoList(musicInfo);    }
}

获取歌单数据顺序分别为:歌曲歌词id,专辑图片id,歌曲名,歌手名,专辑名;
将该函数解析出来的数据通过信号发送到MusicInterface的槽函数中;
在HttpHandle中声明信号:

signals:
    void signalShowMusicInfoList(QStringList musicInfo);

在MusicInterface类中创建一个HttpHandle类的对象,声明接受信号的槽并实现并在构造函数中完成信号与槽的连接:

private slots:
void slotShowMusicInfoList(QStringList musicInfo);

private:
    Ui::MusicInterface *ui;  //播放器界面对象
    HttpHandle *httpHandle; 
MusicInterface::MusicInterface(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MusicInterface),
    httpHandle(new HttpHandle(this))
    {
    	ui->setupUi(this);
    	setWindowIcon(QIcon("(该音乐播放器图标的地址)"));
    	connect(httpHandle, SIGNAL(signalShowMusicInfoList(QStringList)), this, SLOT(slotShowMusicInfoList(QStringList)));
    }

解析音乐源网址JSON数据

在HttpHandle类中声明并实现一个解析音乐源网数据函数:

QString HttpHandle::searchMusicUrl(const QString &id)
{
    //qDebug() << id;
    QString body = QString("types=url&id=%1&source=netease").arg(id);
    QByteArray musicUrl = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicUrl, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析音乐源网址JSON数据失败!错误码:" << error.errorString();
        return QString();
    }

    QJsonObject musicObject = JsonDocument.object();
    return musicObject["url"].toString();
}

解析歌词JSON数据

在HttpHandle类中声明并实现一个解析歌词数据函数:

QString HttpHandle::searchMusicLyric(const QString &id)
{
    //qDebug() << id;
    QString body = QString("types=lyric&id=%1&source=netease").arg(id);
    QByteArray musicLyric = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicLyric, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析歌词JSON数据失败!错误码:" << error.errorString();
        return QString();
    }

    QJsonObject musicObject = JsonDocument.object();
    return musicObject["lyric"].toString();
}

解析专辑图片网址JSON数据

在HttpHandle类中声明并实现一个解析专辑图片网址数据函数:

QString HttpHandle::searchMusicPicUrl(const QString &picId)
{
    //qDebug() << picId;
    QString body = QString("types=pic&id=%1&source=netease").arg(picId);
    QByteArray musicData = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析专辑图片网址JSON数据失败!错误码:" << error.errorString();
        return QString();
    }

    QJsonObject musicPicUrl = JsonDocument.object();
    //qDebug() << musicPicUrl["url"].toString();
    return musicPicUrl["url"].toString();
}

实现搜索歌单控件并测试解析歌单是否正确

在 ui 窗口界面右键搜索歌单控件 lineEdit_search 转到 pressed 槽,于是在该控件输入数据后便会被解析输出歌单(注意要在上述解析数据函数末尾处用去Debug()输出测试):

void MusicInterface::on_lineEdit_search_returnPressed()
{
    QString searchData = ui->lineEdit_search->text(); //获取到用户输入的搜索内容
    httpHandle->searchMusicList(searchData);           //获取解析歌单数据
    
//测试代码
    httpHandle->searchMusicUrl("174956");              //获取解析声源下载地址
    httpHandle->searchMusicLyric("174956");            //获取解析歌词
    httpHandle->searchMusicPicUrl("109951164006892980"); //获取pic对应的音乐专辑图片的网址
}

测试成功后显示如下:
在这里插入图片描述
测试完后注销掉后三排测试代码

实现http协议网络连接类完整代码

http协议网络通信、数据解析类头文件

#ifndef HTTPHANDLE_H
#define HTTPHANDLE_H

#include <QObject>
#include <QNetworkAccessManager>

class HttpHandle : public QObject
{
    Q_OBJECT
public:
    explicit HttpHandle(QObject *parent = nullptr);

    QByteArray postSearch(const QString &body);
    QByteArray getSearch(const QString &url);

    void searchMusicList(const QString &searchData);
    QString searchMusicUrl(const QString &id);
    QString searchMusicLyric(const QString &id);
    QString searchMusicPicUrl(const QString &picId);

signals:
    void signalShowMusicInfoList(QStringList musicInfo);

public slots:

private:
    QNetworkAccessManager *networkAccessManager;
};

#endif // HTTPHANDLE_H

http协议网络通信、数据解析类实现文件

#include "Httphandle.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>

HttpHandle::HttpHandle(QObject *parent) : QObject(parent),
    networkAccessManager(new QNetworkAccessManager(this))
{

}

QByteArray HttpHandle::postSearch(const QString &body)
{
    QNetworkRequest networkRequest(QUrl("https://l-by.cn/yinyue/api.php"));
    networkRequest.setRawHeader(QByteArray("content-type"), QByteArray("application/x-www-form-urlencoded; charset=UTF-8"));
    QEventLoop eventLoop;
    QNetworkReply *networkReply = networkAccessManager->post(networkRequest, body.toUtf8());
    connect(networkReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    return networkReply->readAll();
}

QByteArray HttpHandle::getSearch(const QString &url)
{
    QNetworkRequest networkRequest(url);
    QEventLoop eventLoop;
    QNetworkReply *networkReply = networkAccessManager->get(networkRequest);
    connect(networkReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    return networkReply->readAll();
}

void HttpHandle::searchMusicList(const QString &searchData)
{
    QString body = QString("types=search&count=30&source=netease&pages=1&name=%1").arg(searchData);//30是一面歌曲数,1是页面数,可以用%2添加参数进行翻页,后面加上.arg(int)
    QByteArray musicData = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析音乐列表JSON数据失败!错误码:" << error.errorString();
        return;
    }

    QJsonArray musicInfoArray = JsonDocument.array();
    for (int i = 0; i < musicInfoArray.size(); ++i) {
        QJsonObject musicObject = musicInfoArray[i].toObject();
        QStringList musicInfo;
        QString id = QString::number(musicObject["id"].toInt());
        QString picId = musicObject["pic_id"].toString();
        QString name = musicObject["name"].toString();

        QJsonArray artistArray = musicObject["artist"].toArray();
        QString artist;
        for (int j = 0; j < artistArray.size(); ++j) {
            artist = artist + artistArray[j].toString() + ',';
        }
        artist.chop(1); //删除最后一个多余的','
        QString album = musicObject["album"].toString();
        musicInfo << id << picId << name << artist << album;
        emit signalShowMusicInfoList(musicInfo);    }
}

QString HttpHandle::searchMusicUrl(const QString &id)
{
    //qDebug() << id;
    QString body = QString("types=url&id=%1&source=netease").arg(id);
    QByteArray musicUrl = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicUrl, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析音乐源网址JSON数据失败!错误码:" << error.errorString();
        return QString();
    }

    QJsonObject musicObject = JsonDocument.object();
    //qDebug() << musicObject["url"].toString();
    return musicObject["url"].toString();
}

QString HttpHandle::searchMusicLyric(const QString &id)
{
    //qDebug() << id;
    QString body = QString("types=lyric&id=%1&source=netease").arg(id);
    QByteArray musicLyric = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicLyric, &error);
    if (error.error != QJsonParseError::NoError) {
        //qDebug() << "解析歌词JSON数据失败!错误码:" << error.errorString();
        return QString();
    }

    QJsonObject musicObject = JsonDocument.object();
    //qDebug() << musicObject["lyric"].toString();
    return musicObject["lyric"].toString();
}

QString HttpHandle::searchMusicPicUrl(const QString &picId)
{
    //qDebug() << picId;
    QString body = QString("types=pic&id=%1&source=netease").arg(picId);
    QByteArray musicData = postSearch(body);

    QJsonParseError error;
    QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "解析专辑图片网址JSON数据失败!错误码:" << error.errorString();
        return QString();
    }

    QJsonObject musicPicUrl = JsonDocument.object();
    //qDebug() << musicPicUrl["url"].toString();
    return musicPicUrl["url"].toString();
}

实现双击点播

新创建一个音乐播放类(MusicPlayer),该类中使用Map容器将音乐列表与其对应的歌曲信息保存下来,根据系统QMediaplayer里的 play()函数可自动解析音源网址并播放,从而达到点播的效果;
MusicPlayer 音乐播放、歌词解析类头文件

#ifndef MUSICPLAYER_H
#define MUSICPLAYER_H

#include <QMediaPlayer>
#include <QMap>
#include <QTime>

class MusicPlayer : public QMediaPlayer
{
    Q_OBJECT
public:
    explicit MusicPlayer(QObject *parent = nullptr);

    QString parsingLyrics(QString lyric);

signals:
    void getTextEditLine(int line);

public slots:
    void slotPositionChange(qint64 ms);

private:
    QMap<qint64, int> lyricTime;
};

#endif // MUSICPLAYER_H

MusicPlayer 音乐播放、歌词解析类实现文件

#include "MusicPlayer.h"

MusicPlayer::MusicPlayer(QObject *parent) : QMediaPlayer(parent)
{
    setVolume(50);
    setNotifyInterval(200);
    connect(this, SIGNAL(positionChanged(qint64)), this, SLOT(slotPositionChange(qint64)));
}

QString MusicPlayer::parsingLyrics(QString lyric)
{
    QStringList lyricList = lyric.split('\n'); //以'\n'为界限拼接字符串
    QString newLyric;
    lyricTime.clear();
    int line = 0;
    for (int i = 0; i < lyricList.size(); ++i) {
        QStringList lyricLineList = lyricList[i].split(']');
        if (lyricLineList.size() != 2 || lyricLineList[1].size() < 1) {
            continue;
        }
        QString lyricLine = lyricLineList[1].trimmed(); //去掉首位空格
        newLyric = newLyric + lyricLine + "\r\n";

        QString time = lyricLineList[0].remove('[');
        if (time.size() == 8) {
            time = time + '0'; //老歌时间补0
        }
        QTime ms = QTime::fromString(time, "mm:ss.zzz");
        lyricTime[ms.msecsSinceStartOfDay()] = line ++;
    }
    //qDebug() << lyricTime;
    return newLyric;
}

void MusicPlayer::slotPositionChange(qint64 ms)
{
    if (lyricTime.empty()) {
        return;
    }
    QMap<qint64, int>::iterator it = lyricTime.upperBound(ms);
    int endLine = (lyricTime.end() - 1).value();
    if (it == lyricTime.end()) {
         -- it;
        //qDebug() << it.value();
        emit getTextEditLine(it.value());
    }
    else {
        if (it.value() + 5 <= endLine) {
            emit getTextEditLine(it.value() + 5);
        }
        //qDebug() << it.value() - 1;
        emit getTextEditLine(it.value() - 1);
    }
}

专辑图片处理

GraphicsView专辑图片处理类头文件

#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H

#include <QGraphicsView>
#include <QImage>
#include <QGraphicsScene>
#include "DiskItem.h"
#include "NeedleItem.h"

class GraphicsView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit GraphicsView(QWidget *parent = nullptr);

    void paintEvent(QPaintEvent *pe);

    void resizeEvent(QResizeEvent *re);

    void reflushMusicPic(const QImage& pic);

    QImage makeARGB32Image(QImage musicPic);

    QImage makeCircleImage(QImage argb32Image);

    QImage makeDiskImage(QImage circleImage);

    void diskItemAnimaStart();

    void diskItemAnimaPause();

signals:

public slots:

private:
    QImage image;
    QGraphicsScene *scene;
    DiskItem *diskItem;
    NeedleItem *needleItem;
};

#endif // GRAPHICSVIEW_H

GraphicsView专辑图片处理类实现文件

#include "GraphicsView.h"
#include <QPainter>
#include <QResizeEvent>

GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent),
  scene(new QGraphicsScene(this)),
  diskItem(new DiskItem(this)),
  needleItem(new NeedleItem(this))
{
    image.load(":/image/背景图4.png");

    setScene(scene);
    scene->addItem(diskItem);
    scene->addItem(needleItem);
}

void GraphicsView::paintEvent(QPaintEvent *pe) //绘制事件函数
{
    QPainter painter(viewport());
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.drawImage(rect(), image);

    QGraphicsView::paintEvent(pe);
}

void GraphicsView::resizeEvent(QResizeEvent *re)
{
    int x = re->size().width();
    int y = re->size().height();
    scene->setSceneRect(x / -2.0, y / -2.0, x, y);
    diskItem->setPos(0, 0);
    needleItem->setPos(-80, -220);

    QGraphicsView::resizeEvent(re);
}

void GraphicsView::reflushMusicPic(const QImage &pic)
{
    //image = pic;
    //pic.save("1.png");
    QImage argb32Image = makeARGB32Image(pic);
    //argb32Image.save("2.png");
    QImage circleImage = makeCircleImage(argb32Image);
    //circleImage.save("3.png");
    QImage diskImage = makeDiskImage(circleImage);
    //diskImage.save("4.png");
    diskItem->setImage(diskImage);
    update();  //触发绘制事件
}

QImage GraphicsView::makeARGB32Image(QImage musicPic)
{
    QImage circle(":/image/circleMask.png");
    musicPic = musicPic.scaled(circle.size(), Qt::KeepAspectRatio);
    QImage fixedImage(circle.size(), QImage::Format_ARGB32_Premultiplied);
    QPainter painter(&fixedImage);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.setCompositionMode(QPainter::CompositionMode_Source);
    painter.fillRect(fixedImage.rect(), Qt::transparent);
    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
    painter.drawImage(fixedImage.rect(), musicPic);
    painter.end();

    return fixedImage;
}

QImage GraphicsView::makeCircleImage(QImage argb32Image)
{
     QImage circle(":/image/circleMask.png");
     QPainter painter(&argb32Image);
     painter.setRenderHint(QPainter::SmoothPixmapTransform);
     painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
     painter.drawImage(0, 0, circle);
     painter.end();
     return argb32Image;
}

QImage GraphicsView::makeDiskImage(QImage circleImage)
{
     QImage disk(":/image/disk.png");
     QPainter painter(&disk);
     painter.setRenderHint(QPainter::SmoothPixmapTransform);
     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
#if 1
     painter.drawImage(QPointF((disk.width() - circleImage.width()) / 2.0,
                              (disk.height() - circleImage.height()) / 2.0), circleImage);
#else
     QRect rec = circleImage.rect();
     QPoint centerPoint = disk.rect().center();  //重合中心点
     rec.moveCenter(centerPoint);
     painter.drawImage(rec, circleImage);
#endif
     painter.end();
     return disk;
}

void GraphicsView::diskItemAnimaStart()
{
    diskItem->startAnimation();
    needleItem->startAnimation();
}

void GraphicsView::diskItemAnimaPause()
{
    diskItem->pauseAnimation();
    needleItem->pauseAnimation();
}

动态图片处理

实现唱片图片旋转

DiskItem光盘图元旋转类头文件

#ifndef DISKITEM_H
#define DISKITEM_H

#include <QObject>
#include <QGraphicsItem>
#include <QImage>
#include <QPropertyAnimation>

class DiskItem : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)
    Q_PROPERTY(qreal anagle READ rotation WRITE setRotation)
public:
    explicit DiskItem(QObject *parent = nullptr);

    virtual QRectF boundingRect() const;

    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);

    void setImage(const QImage& musicImage);

    void startAnimation();

    void pauseAnimation();

signals:

public slots:

private:
    QImage image;
    QPropertyAnimation *animation;
};

#endif // DISKITEM_H

DiskItem光盘图元旋转类实现文件

#include "DiskItem.h"
#include <QPainter>

DiskItem::DiskItem(QObject *parent) : QObject(parent)
{
    image.load(":/image/4.png");
    animation = new QPropertyAnimation(this, "anagle", this);
    animation->setDuration(2000);
    animation->setStartValue(0);
    animation->setEndValue(360);
    animation->setLoopCount(-1);
}

QRectF DiskItem::boundingRect() const
{
    return QRectF(image.width() / -2.0, image.height() / -2.0, image.width(), image.height());
}

void DiskItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->setRenderHint(QPainter::SmoothPixmapTransform);
    painter->drawImage(boundingRect(), image);
}

void DiskItem::setImage(const QImage &musicImage)
{
    image = musicImage;
    update();
}

void DiskItem::startAnimation()
{
    animation->start();
}

void DiskItem::pauseAnimation()
{
    animation->pause();
}

实现唱针图元摆动

NeedleItem唱针图元摆动类头文件

#ifndef NEEDLEITEM_H
#define NEEDLEITEM_H

#include <QObject>
#include <QGraphicsItem>
#include <QImage>
#include <QPropertyAnimation>

class NeedleItem : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)
    Q_PROPERTY(qreal anagle READ rotation WRITE setRotation)
public:
    explicit NeedleItem(QObject *parent = nullptr);

    virtual QRectF boundingRect() const;

    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);

    void startAnimation();

    void pauseAnimation();

signals:

public slots:

private:
    QImage image;
    QPropertyAnimation *animation;
};

#endif // NEEDLEITEM_H

NeedleItem唱针图元摆动类实现文件

#include "NeedleItem.h"
#include <QPainter>

NeedleItem::NeedleItem(QObject *parent) : QObject(parent)
{
    image.load(":/image/magnetNeedle.png");
    animation = new QPropertyAnimation(this, "anagle", this);
    setTransformOriginPoint(-102, -0.5);
    animation->setDuration(200);
    animation->setLoopCount(1);
}

QRectF NeedleItem::boundingRect() const
{
    return QRectF(image.width() / -2.0, image.height() / -2.0, image.width(), image.height());
}

void NeedleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->setRenderHint(QPainter::SmoothPixmapTransform);
    painter->drawImage(boundingRect(), image);
}

void NeedleItem::startAnimation()
{
    animation->setStartValue(0);
    animation->setEndValue(20);
    animation->start();
}

void NeedleItem::pauseAnimation()
{
    animation->setStartValue(20);
    animation->setEndValue(0);
    animation->start();
}

关于界面

AboutInterface关于界面窗口类头文件

#ifndef ABOUTINTERFACE_H
#define ABOUTINTERFACE_H

#include <QWidget>

namespace Ui {
class AboutInterface;
}

class AboutInterface : public QWidget
{
    Q_OBJECT

public:
    explicit AboutInterface(QWidget *parent = 0);
    ~AboutInterface();

private:
    Ui::AboutInterface *ui;
};

#endif // ABOUTINTERFACE_H

AboutInterface关于界面窗口类实现文件

#include "AboutInterface.h"
#include "ui_AboutInterface.h"

AboutInterface::AboutInterface(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::AboutInterface)
{
    ui->setupUi(this);
    setWindowIcon(QIcon(":/image/背景图1.jpg"));
    setWindowFlag(Qt::WindowStaysOnTopHint); //界面置顶
    setFixedSize(size());
}

AboutInterface::~AboutInterface()
{
    delete ui;
}

音乐播放器实现演示图

在这里插入图片描述

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
一个完整的毕业设计带说明讲解 该音乐播放器是本地音乐播放器,用户可以将本地音乐添加到音乐曲库中,支持歌词显示及样式设置,支持用户注册,用户登录后可以定制自己的音乐播放列表。该项目主要应用到了Qt的数据库操作和媒体库使用。 二、功能: 【创建新列表】: 只有用户登录之后,才能创建新列表。播放列表是针对每个登录用户显示的,用户与用户之间的播放列表可以不同。 【登录/注册】: 用户可以注册账号,然后登录自己的账号,定制自己的播放列表。 【设置】: 【添加歌曲】:点击后弹出的窗体中,列表显示曲库中的所有歌曲,下面有三个按钮,“添加文件夹”按钮支持用户选择本地歌曲文件夹,然后将该文件夹下的所有歌曲都添加到曲库中;“添加音乐”按钮需选择音乐文件后添加到曲库;“删除音乐”按钮将用户已选择的歌曲从曲库中移除。 【字体样式】:该窗口用来调整主窗口中歌词的样式,包括歌词的字体、字形、大小,以及歌词的普通颜色和高亮颜色。 【个人资料】:这个窗口用来显示已登录用户的个人信息资料,包括登录状态、用户头像、用户昵称、个性签名和注册时间。用户可以通过点击头像来重新设置自己的头像,还可以更新自己的个性签名,更改设置后点击保存。 【歌词路径】:因为该播放器是本地音乐播放器,所以歌词路径是根据用户添加歌曲时的路径确定的,当用户的歌词不在默认路径时,需要用户在此处手动设置歌词的路径。 【搜索】: 支持搜索添加到曲库中的歌曲。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值