ui界面我就不细说了,可以自行参照设计,实现的功能有:
1.搜索网络歌曲,但是这个网络歌曲是自己模拟的服务器,与各大音乐软件服务器或者api什么的无关
2.歌词同步
3.随机播放,上一首,下一首,暂停播放。主要就是这些按钮控件。
最右边的按键就是歌曲列表与歌词页面的切换按钮
最左边的为随机播放功能开启和关闭
一、演示:


文件夹按钮为:有config文件配置,但是我这里没有进行显示,理由就是同上面显示的一样的操作,为了赶进度就没实现了,但是道理是一样的。
学完本项目可以了解一下qt中的:http请求,json分析,数据库操作,多线程操作,以及文件操作,专辑图像处理本程序并未实现,大家可以自行补充qt中的图像处理相关知识。
所以接下来我们先实现搜索网络歌曲部分。
以下是实现http功能的源代码
二、http请求部分(musichttp)
musichttp.h
#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
#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音乐下载/";
//歌曲文件夹地址
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
发表评论