保姆级教学QT实战项目:基于QT的音乐播放器(一)

yuan莫 2024-07-09 14:05:03 阅读 58

UI界面我就不细说了,可以自行参照设计,实现的功能有:

1.搜索网络歌曲,但是这个网络歌曲是自己模拟的服务器,与各大音乐软件服务器或者API什么的无关

2.歌词同步

3.随机播放,上一首,下一首,暂停播放。主要就是这些按钮控件。

 

最右边的按键就是歌曲列表与歌词页面的切换按钮

最左边的为随机播放功能开启和关闭

一、演示:

文件夹按钮为:有config文件配置,但是我这里没有进行显示,理由就是同上面显示的一样的操作,为了赶进度就没实现了,但是道理是一样的。

学完本项目可以了解一下QT中的:http请求,json分析,数据库操作,多线程操作,以及文件操作,专辑图像处理本程序并未实现,大家可以自行补充QT中的图像处理相关知识。

所以接下来我们先实现搜索网络歌曲部分。

以下是实现http功能的源代码

 

二、http请求部分(MusicHttp)

MusicHttp.h 

<code>#include <QObject>

#include <QNetworkAccessManager>//处理网络请求和接收响应的一个核心类

#include <QUrl>//url地址

#include <QNetworkReply>//接收返回数据

#include <QNetworkRequest>//发送请求

#include <QFile>//文件操作,读取数据需要保存在文件

#include <QDebug>

class MusicHttp : public QObject

{

Q_OBJECT

public:

//枚举请求状态

enum MusicHttpState{

MusicFailHttp,

MusicSuccessHttp,

};

explicit MusicHttp(const QString &filename,QObject *parent = nullptr);

bool GetHttpState();

void setFilename(const QString &value);

void onGet(const QString& httpurl);

void onreadyRead();

QByteArray onreadData();

void onhandFinished();

void onhandError(QNetworkReply::NetworkError code);

signals:

void readyRead();

void error();

public slots:

private:

QString filename;//文件名

QNetworkAccessManager* networkManager;//请求对象

enum MusicHttpState httpstate;//判断请求成功还是失败

};

#endif // MUSICHTTP_H

MusicHttp.cpp 

/*

第一,我们要创建一个网络管理对象,用于发送和接收http请求

同时我们还需要一个文件,用于存放请求接受的数据,因为搜索一首歌可以有多个返回结果,所以每次都需要重新写入文件,我用的是

if(QFile::exists(filename))

QFile::remove(filename);

第二,我自己枚举了请求状态,成功或失败都应该进行处理,成功可以返回搜索结果,失败可以弹出对话框,比如说因为网络问题请求失败

第三,只要连接成功并且接收到数据,QNetworkReply会发出readyRead信号,但是如果文件太大,那会分几次发送,所以我连接了onreadyRead函数,对接受到的数据进行写入,只有当数据接收完,该类发送finished的时候我自定义一个readyRead信号,接受到自定义的信号然后对文件进行读取,所以有两个readyRead信号,不要搞混淆了。一个是自定义,一个是QNetworkReply的。不过该类在连接失败的时候也会发送finished信号,所以发送了一个自定义的错误信号,可以对该信号进行捕获做出对应的处理操作。

第四,可能onGet(const QString& httpurl),可能对这个存在不理解,为什么是这个参数,而且没有调用,但是我们是要根据按下搜索的回车键进行搜索,与其他类配合使用,所以先记下这个参数,往后其他类实现会提及。

第五,实际上我们得到的是json数据,但是这个json数据是我自己参照写的,需要对这个json进行分析,后面有类会对其进行分析,如果要得到真正的json文件需要用到爬虫,本人不会,所以只好自己仿制了。

第六,用到的QT中的类还比较简单,有需要的伙伴可以自行查看帮助手册

*/

#include "musichttp.h"

MusicHttp::MusicHttp(const QString &filename,QObject *parent) :

QObject(parent),filename(filename)

{

networkManager = new QNetworkAccessManager(this);

//将请求状态初始化为成功

httpstate=MusicHttpState:: MusicSuccessHttp;

}

//发送请求部分

void MusicHttp::onGet(const QString& httpurl)

{

if(QFile::exists(filename)){

QFile::remove(filename);

}

//连接服务器的返回状态初始化为成功

httpstate=MusicHttpState:: MusicSuccessHttp;

//创建url对象,也就是设置url地址

QUrl url(httpurl);

//创建一个请求对象,用于发送请求

QNetworkRequest request(url);

//发送请求,返回一个reply对象

//该返回对象接受到数据会发送readyRea信号

QNetworkReply *reply = networkManager->get(request);

connect(reply,&QNetworkReply::readyRead,this,&MusicHttp::onreadyRead);

//数据发送完毕或者是请求失败,发出finished信号,处理该信号

connect(reply,&QNetworkReply::finished,this,&MusicHttp::onhandFinished);

//请求失败处理部分

//对请求失败进行输出,输出失败原因

connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),\

this,SLOT(onhandError(QNetworkReply::NetworkError)));

}

//处理请求完成

void MusicHttp::onhandFinished()

{

QNetworkReply *reply =(QNetworkReply *)this->sender();

//如果不是请求失败,则发出readyRead信号,表示可以读取数据

if(reply->error() == QNetworkReply::NoError){

emit readyRead();

}

reply->deleteLater();

}

//处理请求失败

void MusicHttp::onhandError(QNetworkReply::NetworkError code)

{

qDebug()<<"error code:"<<code;

httpstate=MusicHttpState:: MusicFailHttp;

emit error();

}

//处理接受到的数据

void MusicHttp::onreadyRead()

{

//连接该槽函数的对象是局部变量,所以要先获取是谁发送的信号

QNetworkReply *reply =(QNetworkReply *)this->sender();

//读取数据写入缓冲区

QByteArray data =reply->readAll();

//准备一个文件,将缓冲区数据以追加的方式写入文件

QFile file(filename);

bool ok = file.open(QFile::WriteOnly|QFile::Append);

if(!ok){

qDebug()<<"fail open "<<filename<<"to write \n Error:"<<file.errorString();

return;

}

file.write(data);

file.close();

return;

}

//对保存的数据进行读取

QByteArray MusicHttp::onreadData()

{

QFile file(filename);

bool ok = file.open(QFile::ReadOnly);

if(!ok){

qDebug()<<"fail open "<<filename<<"to Read \n Error:"<<file.errorString();

return QByteArray();

}

QByteArray data = file.readAll();

file.close();

return data;

}

//构造函数

void MusicHttp::setFilename(const QString &value)

{

filename = value;

}

//用户查询成功还是失败

bool MusicHttp::GetHttpState()

{

return httpstate==MusicHttpState::MusicSuccessHttp ? true : false;

}

实现网络请求部分,接下来就是搜索功能实现部分了

三、搜索功能部分(MusicSearch)

准备一个json文件,以下是我自己仿的,仅供学习使用。filename:你瞒我瞒.json

MusicSearch.h

<code>#ifndef MUSICSEARCH_H

#define MUSICSEARCH_H

#include <QObject>

#include <QJsonObject>

#include <QJsonArray>

#include <QJsonParseError>

#include <QJsonDocument>

#include "musichttp.h"

#include "musicinformation.h"

class MusicSearch : public QObject

{

Q_OBJECT

public:

explicit MusicSearch(QObject *parent = nullptr);

signals:

showMusicInfo(const QVector<MusicInformation* > musicInfoList);

public slots:

//搜索对应的歌曲名方法方法,

void search(const QString& music);

//读取歌曲文件

void onreadyRead();

//解析json数据

void parseMusicJsonData(const QByteArray jsondata);

//清空容器

void clearMusicList();

private:

MusicHttp* musicHttp;

//创建容器,里面的类型为MusicInformation*,下一部分提及

QVector<MusicInformation* > musicInfoList;

};

#endif // MUSICSEARCH_H

MusicSearch.cpp 

/*

第一,创建MusicHttp对象,可以使用里面的接口方法,当自定义的readyRead信号发出的时候,就可以对其进行读取分析,在MusicHttp部分说了,得到的是json数据。

第二,//实现搜索歌曲 void MusicSearch::search(const QString &music) 该函数主要是在搜索栏按下的时候调用,根据歌曲在服务器寻找对应的歌曲json文件,而我模拟的web服务器主要地址就是

http://localhost/QQ音乐下载/,也就是从这里开始找。

第三,这里我封装了一个MusicInfomation的类,主要是用于存储歌曲信息,这里还没有讲,如果不用也是一样的,自定义QString musicMp3Url,QString musicLrcUrl,...。添加这个类主要是可以创建一个对象,发生信号的时候把容器发送过去,再一个个在ui界面进行显示就比较方便

第四,注意json文件的错误信号,解析失败的时候要对其进行处理。

第五,当解析完所有的JSON数据,并且插入容器的时候,就可以发送信号,将容器发送过去,主界面进行捕获,就可以显示在ui界面上

*/

#include "musicsearch.h"

MusicSearch::MusicSearch(QObject *parent) : QObject(parent)

{

musicHttp = new MusicHttp("music.json",this);

//连接MusicHttp的readyRead信号,对其进行读取

connect(musicHttp,&MusicHttp::readyRead,this,&MusicSearch::onreadyRead);

}

//实现搜索歌曲

void MusicSearch::search(const QString &music)

{

QString httpurl = QString("http://localhost/QQ音乐下载/%1/%2.json").arg(music).arg(music);

musicHttp->onGet(httpurl);

}

//获取从服务器返回的数据

void MusicSearch::onreadyRead()

{

QByteArray data = musicHttp->onreadData();

//对接收到的json文件进行解析

parseMusicJsonData(data);

}

//解析json文件

void MusicSearch::parseMusicJsonData(const QByteArray jsondata)

{

QJsonParseError jsonParseError;

QJsonDocument musicDocument =QJsonDocument::fromJson(jsondata,&jsonParseError);

if(musicDocument.isEmpty()){

qDebug()<<"Fail to parse data:"<<musicDocument<<"Error:"<<jsonParseError.errorString();

return ;

}

QJsonObject musicObject = musicDocument.object();

QJsonArray musicArray = musicObject["list"].toArray();

for(int i=0;i<musicArray.size();i++){

MusicInformation* music = new MusicInformation;

QJsonObject object = musicArray[i].toObject();

QString musicName = object["musicName"].toString();

QString albumName = object["albumName"].toString();

QString duration =QString::number(object["duration"].toInt());

QString musicPath = object["path"].toString();

QString musicMp3 = object["mp3"].toString();

QString musicLrc = object["lyric"].toString();

music->musicName = musicName;

music->albumName = albumName;

music->duration = duration.toInt();

music->musicLrcName = musicLrc;

music->musicMp3Url = QString(music->bodyUrl+musicPath+"/"+musicMp3);

music->musicLrcUrl = QString(music->bodyUrl+musicPath+"/"+musicLrc);

music->musicAlbumUrl=QString(music->bodyUrl+musicPath+"/"+albumName+".jpg");

//将得到的歌曲信息插入歌曲容器

musicInfoList.append(music);

}

//发送信号,可以显示歌曲

emit showMusicInfo(musicInfoList);

}

//清空歌曲列表容器

void MusicSearch::clearMusicList()

{

qDeleteAll(musicInfoList.begin(), musicInfoList.end());

musicInfoList.clear();

}

四、歌曲信息类,MusicInfomation 

/*

这里没什么说的,就是一些成员变量,同时有QT自己生成的构造函数,可以根据自己需要添加成员变量,另外这里不仅有网络歌曲,后面还需要播放本地歌曲,所以就合在了一块儿.主要就是我服务器的基本路径,每个人都不同,这只是我从该路径开始而已

*/

#ifndef MUSICINFORMATION_H

#define MUSICINFORMATION_H

#include <QObject>

#include <QDebug>

#include <QString>

class MusicInformation : public QObject

{

Q_OBJECT

public:

explicit MusicInformation(QObject *parent = nullptr);

//主地址,服务器基本路径

QString bodyUrl="http://localhost/QQ音乐下载/";code>

//歌曲文件夹地址

QString musicUrl;

//mp3地址

QString musicMp3Url;

//歌词地址

QString musicLrcUrl;

//专辑图片地址

QString musicAlbumUrl;

//歌曲名

QString musicName;

//专辑名

QString albumName;

//歌曲时长

qint16 duration;

//歌词名

QString musicLrcName;

//本地mp3地址

QString musicLocalMp3Path;

//本地歌词地址

QString musicLocalLrcPath;

//本地专辑地址

QString musicLocalAlmPath;

QString getMusicUrl() const;

void setMusicUrl(const QString &value);

QString getMusicMp3Url() const;

void setMusicMp3Url(const QString &value);

QString getMusicLrcUrl() const;

void setMusicLrcUrl(const QString &value);

QString getMusicAlbumUrl() const;

void setMusicAlbumUrl(const QString &value);

QString getMusicName() const;

void setMusicName(const QString &value);

QString getAlbumName() const;

void setAlbumName(const QString &value);

qint16 getDuration() const;

void setDuration(const qint16 &value);

QString getMusicLrcName() const;

void setMusicLrcName(const QString &value);

QString getMusicLocalMp3Path() const;

void setMusicLocalMp3Path(const QString &value);

QString getMusicLocalLrcPath() const;

void setMusicLocalLrcPath(const QString &value);

QString getMusicLocalAlmPath() const;

void setMusicLocalAlmPath(const QString &value);

signals:

public slots:

private:

};

#endif // MUSICINFORMATION_H

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。