保姆级教学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
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。