实现的功能
1.可以播放本地音乐
2.实现常用功能(上下曲,播放/暂停,显示播放时长)
3.通过网易云API搜索歌曲
实现步骤
1.在pro文件里面添加multimedia库和network库
2.设计好自己的UI界面
3.添加自己需要的头文件并定义自己需要的变量
4.打开自己存放歌曲的目录,将歌曲添加到歌曲列表然后进行播放
5.通过信号与槽机制实现常用的功能
6.接入网易云API进行歌曲搜索
ui界面展示

代码模块展示
添加本地文件
file = QFileDialog::getOpenFileName(this,
"Open File",
"D:/Music",
"mp3 Files (*.mp3)");//打开MP3文件,如果需要添加其余音频文件,只需继续添加过滤项即可
playlist->addMedia(QUrl(file));//将自己需要的MP3文件添加入播放列表
//以下是去掉前面的路径并且追加显示到plainTextEdit(将名字复制到另一个字符串)
int fi=0,af=9;//fi为新字符串的开始位置,af为歌曲名字的第一个位置(自己的路径)
QString s;//新字符串
while(file[af]!='\0')将歌曲名字移动到数组开头
{
s[fi]=file[af];
fi++;
af++;
}
s[fi]='\0';//添加字符串结束标志
ui->plainTextEdit->appendPlainText(s);//显示到plainTextEdit
播放/暂停
//通过标志位来实现播放与暂停
if(x==0) //如果是停止状态或暂停就播放
{
player->play();
x=1; //置1下一次点击就会暂停
}
else if(x==1) //如果是播放状态就暂停
{
player->pause();
x=0; //置0下一次点击就会播放
}
下一曲
//点击下一曲,如果当前歌曲是最后一首歌曲,就跳到第一首歌,其余则直接跳到下一首
int m_Value=playlist->currentIndex(); //当前歌曲是第几个
int m_Amount=playlist->mediaCount(); //总歌曲数量
if(m_Value<m_Amount) //判断当前歌曲是否为最后一首
{
m_Value=m_Value+1; //播放的位置+1
playlist->setCurrentIndex(m_Value); //重新设置播放的位置
player->play();
}
else
{
m_Value=0;
playlist->setCurrentIndex(m_Value); //跳到第一首
player->play();
}
上一曲与之类似
时间显示
//通过槽函数实现
void Widget::timechange(qint64 duration)
{
int secs = duration/1000; //全部秒数
int mins = secs/60;//分
secs = secs % 60;//秒
QString str=QString::asprintf("%d:%d",mins,secs);//转换为字符串
ui->lcdNumber->display(str);//用lcdNumber进行显示
}
正在播放歌曲显示
//通过信号与槽机制检测文件是否变化
void Widget::onDurationChanged(qint64 duration) //文件时长变化,更新当前播放文件名显示播放文件数据总大小的信号, 它可以获得文件时间长度。
{
ui->horizontalSlider->setMaximum(duration); //设置进度条最大值 也就是歌曲时长 ms
int m_Value=playlist->currentIndex();//获取当前歌曲的位置
QTextBlock textLine=doc->findBlockByNumber (m_Value) ;//获取当前文本中的一段
QString str=textLine.text();//将获取后的数据转为字符串
int fi=0,af=9;
QString s;
if(str[0]=='D')//判断是否为本地文件(我的歌是在D盘里面的,所以第一个字符是D)
{
while(str[af]!='\0')
{
s[fi]=str[af];
fi++;
af++;
}
s[fi]='\0';
ui->lineEdit->setText(s);
}
else
ui->lineEdit->setText(str);
}
进度条显示
void Widget::onPositionChanged(qint64 position)//当前文件播放位置变化,更新进度显示播放到什么位置的信号, 参数是以毫秒来计算的。
{
if(ui->horizontalSlider->isSliderDown())
return;//如果手动调整进度条,则不处理
ui->horizontalSlider->setSliderPosition(position);//设置进度条的位置
}
搜索歌曲ID
void Widget::on_b_search_clicked()
{
ui->music_m->clear();
QString str,s;
s=ui->l_search->text();//获取在搜索框输入的数据
str="http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={"+s+"}&type=1&offset=0&total=true&limit=1";//接入网易云API并且传入需要搜索的数据和返回的数量
QNetworkRequest request; //定义一个请求对象
request.setUrl(str); //将请求格式设置给请求对象
manager->get(request); //请求
}
解析返回的数据
void Widget::databack(QNetworkReply *reply)
{
searchInfo=reply->readAll(); //读取返回的全部数据
QJsonParseError err; //错误信息对象
QJsonDocument json_recv = QJsonDocument::fromJson(searchInfo,&err);//将json文本转换为 json 文件对象
if(err.error != QJsonParseError::NoError) //判断是否符合语法
{
qDebug() <<"搜索歌曲Json获取格式错误"<< err.errorString();
return;
}
QJsonObject totalObject = json_recv.object();
QStringList keys = totalObject.keys(); // 列出json里所有的key
if(keys.contains("result")) //如果有结果
{ //在 json 文本中 {}花括号里面是QJsonObject对象, []方括号里面是QJsonArray
QJsonObject resultObject = totalObject["result"].toObject(); //就将带 result 的内容提取后转换为对象
QStringList resultKeys = resultObject.keys(); //保存所有key
if(resultKeys.contains("songs")) //如果 key 为songs ,代表找到了歌曲
{
QJsonArray array = resultObject["songs"].toArray();
for(auto i : array) //开始获取歌曲中的信息
{
QJsonObject object = i.toObject();
musicId = object["id"].toInt(); // 音乐id
musicDuration = object["duration"].toInt(); // 音乐长度
musicName = object["name"].toString(); // 音乐名
mvId = object["mvid"].toInt(); // mvid
QStringList artistsKeys = object.keys();
if(artistsKeys.contains("artists")) //如果result中包含了 artists
{
QJsonArray artistsArray = object["artists"].toArray(); //将 artist 的内容提取后保存
for(auto j : artistsArray)
{
QJsonObject object2 = j.toObject();
singerName = object2["name"].toString(); // 歌手名
}
}
if(artistsKeys.contains("album")) //包含了专辑
{
QJsonObject albumObjct = object["album"].toObject();
albumName = albumObjct["name"].toString(); // 专辑名
}
ui->music_m->appendPlainText("音乐ID:"+QString::number(musicId));
ui->music_m->appendPlainText("音乐名:"+musicName);
ui->music_m->appendPlainText("歌手名:"+singerName);
ui->music_m->appendPlainText("总时长:"+QString::number(musicDuration));
ui->music_m->appendPlainText("专辑名:"+albumName);
}
}
}
QString url;
url=QString("https://music.163.com/song/media/outer/url?id=%0").arg(musicId);//通过网网易云API传入之前返回的歌曲的ID实现播放
playlist->addMedia(QUrl(url)); //添加一音乐到播放列表中
ui->plainTextEdit->appendPlainText(musicName); //用于显示
}
遇到的问题:
1.网易云的API(自己在网上找的)
有关评论
http://music.163.com/api/v1/resource/comments/R_SO_4_{歌曲ID}?limit=20&offset=0
limit:返回数据条数(每页获取的数量),默认为20,可以自行更改
offset:偏移量(翻页),offset需要是limit的倍数
type:搜索的类型
歌单
https://music.163.com/api/playlist/detail?id={歌单ID}
网易云音乐每日推荐各种神奇歌单也是它的一大特色,我们可以利用这个api获取歌单里的所有歌曲信息。
用户信息
https://music.163.com/api/v1/user/detail/{用户ID}
歌词
https://music.163.com/api/song/lyric?id={歌曲ID}&lv=1&kv=1&tv=-1
搜索结果
http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={搜索内容}&type=1&offset=0&total=true&limit=20
limit:返回数据条数(每页获取的数量),默认为20,可以自行更改
offset:偏移量(翻页),offset需要是limit的倍数
type:搜索的类型
type=1 单曲
type=10 专辑
type=100 歌手
type=1000 歌单
type=1002 用户
type=1004 MV
type=1006 歌词
type=1009 主播电台
歌手专辑
http://music.163.com/api/artist/albums/{歌手ID}?id={歌手ID}&offset=0&total=true&limit=10
专辑信息
http://music.163.com/api/album/{专辑ID}?ext=true&id={专辑ID}&offset=0&total=true&limit=10
歌曲信息
http://music.163.com/api/song/detail/?id={歌曲ID}&ids=%5B{歌曲ID}%5D
MV
http://music.163.com/api/mv/detail?id={MV的ID}&type=mp4
2.可能报的错
qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed
大致说,Qt模块中是包含了OpenSSL库的,但是这些库不会自动部署到应用程序中。开发人员希望使用SSL的同时,它们的用户也安装了相关库。或者确保在当地使用SSL是经过许可
可以安装opssl解决
doRender: Unknown error 0x80040218.
可能是因为没有装解码组件可以去安装一个 LAVFilters:
也可能是因为播放的音乐是VIP音乐(播放VIP音乐就会报这个错)
效果视频单独发布了(用的那个游戏盒子录的屏,跳出来的文件夹没有显示)
源码
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QList>
#include <QMediaContent>
#include <QTextBlock>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void on_pushButton_2_clicked();
void on_pushButton_clicked();
void on_next_clicked();
void on_up_clicked();
void timechange(qint64 duration);
void onDurationChanged(qint64 duration);
void onPositionChanged(qint64 position);
void on_b_search_clicked();
void databack(QNetworkReply *reply);
private:
Ui::Widget *ui;
QString durationTime;
QString positionTime;
QNetworkAccessManager* manager;
QMediaPlayer *player;
QMediaPlaylist *playlist;
QString file;
QTextDocument* doc;
QTextBlock textLine;
QString str;
int i,x;
int musicId,musicDuration,mvId;
QString musicName,singerName,albumName;
QByteArray searchInfo;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QLCDNumber>
#include <QString>
#include <QBrush>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setMinimumSize(600,600);
this->setMaximumSize(600,600);//我固定了窗口的大小
ui->music_m->setReadOnly(true);//将显示信息的组件设置设置为只读
manager = new QNetworkAccessManager(this); //定义并实例化一个网络管家
ui->plainTextEdit->setReadOnly(true);//将显示音乐列表的组件设置为只读
ui->lineEdit->setReadOnly(true);//将显示正在播放音乐的组件设置为只读
this->setWindowTitle("QT播放器");//设置窗口标题
x=0;//初始化标志位
doc=ui->plainTextEdit->document () ; //文本对象
player=new QMediaPlayer(this);
playlist=new QMediaPlaylist(this);//初始化对象
player->setMedia(playlist);//设置播放列表
playlist->setPlaybackMode(QMediaPlaylist::Loop);设置播放模式
//信号与槽机制进行处理
connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(timechange(qint64)));
connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPositionChanged(qint64)));
connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(onDurationChanged(qint64)));
connect(manager,SIGNAL(finished(QNetworkReply *)),this,SLOT(databack(QNetworkReply *)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_2_clicked()
{
file = QFileDialog::getOpenFileName(this,"Open File","D:/Music","mp3 Files (*.mp3)");//打开文件
playlist->addMedia(QUrl(file));//将选中的MP3文件添加到播放列表
//将选中的文件去掉路径后追加显示到plainTextEdit
int fi=0,af=9;
QString s;
while(file[af]!='\0')
{
s[fi]=file[af];
fi++;
af++;
}
s[fi]='\0';
ui->plainTextEdit->appendPlainText(s);
}
void Widget::on_pushButton_clicked()
{
if(x==0) //如果是停止状态或暂停就播放
{
player->play();
x=1;
}
else if(x==1) //如果是播放状态就暂停
{
player->pause();
x=0;
}
}
void Widget::on_next_clicked()
{
int m_Value=playlist->currentIndex();//当前歌曲是第几个
int m_Amount=playlist->mediaCount(); //总歌曲数量
if(m_Value<m_Amount)
{
m_Value=m_Value+1;
playlist->setCurrentIndex(m_Value);
player->play();
}
else
{
m_Value=0;
playlist->setCurrentIndex(m_Value);
player->play();
}
}
void Widget::on_up_clicked()
{
int m_Value=playlist->currentIndex();//当前歌曲是第几个
int m_Amount=playlist->mediaCount(); //总歌曲数量
if(m_Value>0)
{
m_Value=m_Value-1;
playlist->setCurrentIndex(m_Value);
player->play();
}
else
{
m_Value=m_Amount-1;
playlist->setCurrentIndex(m_Value);
player->play();
}
}
void Widget::timechange(qint64 duration)
{
int secs = duration/1000; //全部秒数
int mins = secs/60;//分
secs = secs % 60;//秒
QString str=QString::asprintf("%d:%d",mins,secs);
ui->lcdNumber->display(str);
}
void Widget::onDurationChanged(qint64 duration) //文件时长变化,更新当前播放文件名显示播放文件数据总大小的信号, 它可以获得文件时间长度。
{
ui->horizontalSlider->setMaximum(duration); //设置进度条最大值 也就是歌曲时长 ms
int m_Value=playlist->currentIndex();
QTextBlock textLine=doc->findBlockByNumber (m_Value) ; // 文本中的一段
QString str=textLine.text();
int fi=0,af=9;
QString s;
if(str[0]=='D')
{
while(str[af]!='\0')
{
s[fi]=str[af];
fi++;
af++;
}
s[fi]='\0';
ui->lineEdit->setText(s);
}
else
ui->lineEdit->setText(str);
}
void Widget::onPositionChanged(qint64 position)//当前文件播放位置变化,更新进度显示播放到什么位置的信号, 参数是以毫秒来计算的。
{
if(ui->horizontalSlider->isSliderDown())
return;//如果手动调整进度条,则不处理
ui->horizontalSlider->setSliderPosition(position);
}
void Widget::on_b_search_clicked()
{
ui->music_m->clear();
QString str,s;
s=ui->l_search->text();
str="http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={"+s+"}&type=1&offset=0&total=true&limit=1";
QNetworkRequest request; //定义一个请求对象
request.setUrl(str); //将请求格式设置给请求对象
manager->get(request); //请求
}
void Widget::databack(QNetworkReply *reply)
{
searchInfo=reply->readAll();
QJsonParseError err; //错误信息对象
QJsonDocument json_recv = QJsonDocument::fromJson(searchInfo,&err);//将json文本转换为 json 文件对象
if(err.error != QJsonParseError::NoError) //判断是否符合语法
{
qDebug() <<"搜索歌曲Json获取格式错误"<< err.errorString();
return;
}
QJsonObject totalObject = json_recv.object();
QStringList keys = totalObject.keys(); // 列出json里所有的key
if(keys.contains("result")) //如果有结果
{ //在 json 文本中 {}花括号里面是QJsonObject对象, []方括号里面是QJsonArray
QJsonObject resultObject = totalObject["result"].toObject(); //就将带 result 的内容提取后转换为对象
QStringList resultKeys = resultObject.keys(); //保存所有key
if(resultKeys.contains("songs")) //如果 key 为songs ,代表找到了歌曲
{
QJsonArray array = resultObject["songs"].toArray();
for(auto i : array) //开始获取歌曲中的信息
{
QJsonObject object = i.toObject();
musicId = object["id"].toInt(); // 音乐id
musicDuration = object["duration"].toInt(); // 音乐长度
musicName = object["name"].toString(); // 音乐名
mvId = object["mvid"].toInt(); // mvid
QStringList artistsKeys = object.keys();
if(artistsKeys.contains("artists")) //如果result中包含了 artists
{
QJsonArray artistsArray = object["artists"].toArray(); //将 artist 的内容提取后保存
for(auto j : artistsArray)
{
QJsonObject object2 = j.toObject();
singerName = object2["name"].toString(); // 歌手名
}
}
if(artistsKeys.contains("album")) //包含了专辑
{
QJsonObject albumObjct = object["album"].toObject();
albumName = albumObjct["name"].toString(); // 专辑名
}
ui->music_m->appendPlainText("音乐ID:"+QString::number(musicId));
ui->music_m->appendPlainText("音乐名:"+musicName);
ui->music_m->appendPlainText("歌手名:"+singerName);
ui->music_m->appendPlainText("总时长:"+QString::number(musicDuration));
ui->music_m->appendPlainText("专辑名:"+albumName);
}
}
}
QString url;
url=QString("https://music.163.com/song/media/outer/url?id=%0").arg(musicId);
playlist->addMedia(QUrl(url)); //添加返回的音乐到播放列表中
ui->plainTextEdit->appendPlainText(musicName); //用于显示
}