QT----MP3播放器搜索引擎

代码地址:GitHub
文档与提交记录章节相同,方便查看代码变动。视频教学里的酷狗api已经无法使用,自己摸索了一下,还学到了点爬虫知识。教学视频是我废了好大劲搞来的,三连+关注点赞评论进入个人博客领取啦

1 新建项目

新建项目,为Qwidget
file
新建res文件,去网上找点图标放入
file

1.1 UI设计

按下图设计ui也可以自己设计,美观我暂时就不考虑了只要实现功能
file

添加播放进度条,播放的其他按钮,声音调节进度条
file

1.2 修改背景

自定义一个paintEvent(),把图片画到界面上就行,我还是不用背景了,哈人

void OnlineMp3Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(0,0,width(),height(),QPixmap(":/res/dinyilang.png"));
}

file

1.3 生成所有控件的槽函数

按钮只需要点击槽函数,声音大小调节的进度条需要值变化的槽函数
file
播放音乐进度条需要,这三个槽函数
file
最后就是这么多槽函数
file

1.4 添加必要库和头文件

在.pro文件添加必要库,network multimedia sql
file
添加必要的头文件

#include <QNetworkRequest>          //HTTP的URL管理类
#include <QNetworkAccessManager>    //URL的上传管理
#include <QNetworkReply>            //网页回复数据触发信号的类
#include <QEventLoop>               //提供一种进入和离开事件循环的方法
#include <QJsonArray>               //封装JSON数组
#include <QJsonObject>              //封装JSON对象#include <QMediaPlayer>             //播放音乐相关
#include <QMediaPlaylist>#include <QSqlDatabase>             //数据库相关
#include <QSqlQuery>
#include <QSqlError>#include <QMessageBox>
#include <QTime>
#include <math.h>

2 部分逻辑编写

2.1关闭窗口

在ui界面右击关闭按钮,转到槽,使用click事件,编写代码后我们就可以点击按钮关闭界面

void OnlineMp3Widget::on_btn_close_clicked()
{this->close();
}

2.2 鼠标拖动窗口

定义三个函数,点击移动释放,两个变量。
file
当鼠标左键按下时,把mousePress标志为真,计算鼠标相对于窗口左上角的偏移量,储存在movePoint中;当鼠标移动时获取鼠标的全局位置,并计算移动距离,通过move函数将窗口移动到新位置

//移动事件
void OnlineMp3Widget::mouseMoveEvent(QMouseEvent *event)
{if (mousePress)  // 如果鼠标被按下{QPoint movepos = event->globalPos();  // 获取鼠标当前的全局位置move(movepos - movePoint);  // 移动窗口位置}
}//鼠标释放事件
void OnlineMp3Widget::mouseReleaseEvent(QMouseEvent *event)
{Q_UNUSED(event)  // 避免未使用的参数警告mousePress = false;  // 鼠标释放,标记鼠标状态为未按下
}//鼠标点击事件
void OnlineMp3Widget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton)  // 如果鼠标左键被按下{mousePress = true;  // 标记鼠标状态为按下}movePoint = event->globalPos() - pos();  // 计算鼠标相对于窗口左上角的偏移量
}

3 歌曲数据库搭建,歌曲搜索

3.1 数据库搭建

首先连接数据库,如果不存在的话创建一个数据库

// 1、连接数据库,如果不存在则创建if (QSqlDatabase::contains("song")) // 检查是否存在名为"song"的数据库连接{db = QSqlDatabase::database("song"); // 如果存在,则获取该数据库连接}else{db = QSqlDatabase::addDatabase("QSQLITE"); // 如果不存在,则添加一个SQLite数据库连接db.setDatabaseName("song.db"); // 设置数据库文件名为"song.db"}

使用open打开数据库,使用query作为查询语句,创建歌曲信息表格,表里边有id,歌名,歌手,

// 2、打开数据库,读取数据表if (!db.open()) // 尝试打开数据库{// 打开数据库失败,显示错误信息QMessageBox::critical(nullptr, "错误", db.lastError().text());}else{// 3、定义查询对象,执行数据库操作QSqlQuery query; // 定义数据库查询对象QString qstl = "create table if not exists songlist(id integer , songname text , singername text , album_id text)"; // 创建歌曲列表表格的SQL语句int ret = query.exec(qstl); // 执行SQL语句if (!ret) // 检查SQL执行是否成功{// SQL执行失败,显示错误信息QMessageBox::critical(nullptr, "错误", db.lastError().text());qDebug() << db.lastError();}

创建歌曲记录表格,用于我们搜索后记录,双击后又能再次播放

// 创建歌曲记录表格qstl = "create table if not exists songhistory(id integer primary key autoincrement, songname text , singername text)";ret = query.exec(qstl);if (!ret){QMessageBox::critical(nullptr, "错误", db.lastError().text());}

通过record将搜索记录显示在ListWidget上

// 查询歌曲历史记录表中的数据并显示qstl = "select * from songhistory";if (!query.exec(qstl)) // 执行查询操作{// 查询失败,显示错误信息QMessageBox::critical(nullptr, "错误", db.lastError().text());}while (query.next()) // 遍历查询结果{QString songname, singername;QSqlRecord rec = query.record(); // 获取查询结果的记录int songnamekey = rec.indexOf("songname"); // 获取歌曲名字段在查询结果中的索引int singerkey = rec.indexOf("singername"); // 获取歌手名字段在查询结果中的索引songname = query.value(songnamekey).toString(); // 获取歌曲名singername = query.value(singerkey).toString(); // 获取歌手名QString strshow = songname + "--" + singername; // 构造要显示的字符串QListWidgetItem *item = new QListWidgetItem(strshow); // 创建列表项ui->lw_record->addItem(item); // 添加列表项到列表控件中}

3.2 搜索歌曲并且双击播放

3.2.1点击搜索on_btn_search_clicked

在我们在搜索框输入歌曲名时,首先需要清空搜索队列,并且删除sonlist数据表中的所有数据;根据歌曲名称,使用酷狗的api构建网络搜索的URL;调用httpAccess函数发起http响应,使用loop等待http请求结束,一旦完成finish信号发出,数据将会储存在JsonData中。

static QString kugouSearchApi = "http://mobilecdn.kugou.com/api/v3/search/song?";
static QString kugouDownldadApi = "https://wwwapi.kugou.com/yy/index.php?";
void OnlineMp3Widget::on_btn_search_clicked()
{// 清空搜索队列ui->lw_learch->clear();// 清理数据库中已经存储的 hash 等数据QSqlQuery query;QString sql = "delete from songlist;" ;if(!query.exec(sql)){QMessageBox::critical(nullptr,"错误",query.lastError().text());}// 根据用户输入的 MP3 名称发起操作请求QString url = kugouSearchApi + QString("format=json&keyword=%1&page=1&pagesize=20&showtype=1").arg(ui->le_search->text());// 发起 HTTP 请求httpAccess(url);QByteArray JsonData;QEventLoop loop;// 等待 HTTP 请求完成并获取数据auto c = connect(this, &OnlineMp3Widget::finish, [&](const QByteArray &data){JsonData = data;loop.exit(1);});loop.exec();disconnect(c);// 解析获取的 JSON 数据hashJsonAnalysis(JsonData);
}

3.2.2 发送网页请求httpAccess

编写httpAccess函数。首先实例化网络请求,将URL存入,创建一个管理对象manger,用manger发送get请求,查看manger的类里边有完成的信号,使用改信号绑定槽函数netReplay
file

void OnlineMp3Widget::httpAccess(QString url)
{//实例化网络请求操作事项request = new QNetworkRequest;//将url网页地址存入request请求中request->setUrl(url);//实例化网络管理(访问)manager = new QNetworkAccessManager;//通过get,上传具体的请求manager->get(*request);//当网页回复消息,出发finish信号,读取数据connect(manager,&QNetworkAccessManager::finished,this,&OnlineMp3Widget::netReplay);
}

3.2.3 读取网络数据netReplay

使用attribute获得响应的状态码,状态码用于指示服务器对请求的处理结果,例如 200 表示请求成功。如果没有发生错误,读取数据并且发送finish信号

// 读取网络数据槽函数
void OnlineMp3Widget::netReply(QNetworkReply *reply)
{// 获取响应状态码,200 属于正常QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);qDebug() << status_code;// 重定向目标属性reply->attribute(QNetworkRequest::RedirectionTargetAttribute);if (reply->error() == QNetworkReply::NoError){// 如果没有发生网络错误,则读取响应数据QByteArray data = reply->readAll();// 发射自定义的 finish 信号,将响应数据传递给槽函数emit finish(data);}else{// 如果发生了网络错误,则打印错误信息qDebug() << reply->errorString();}
}

3.2.4 解析网页回复数据并存储hashJsonAnalysis

首先我们先打印一下json看看长啥样,把json保存下来打开查看

QFile file("output.json");if(file.open(QIODevice::WriteOnly | QIODevice::Text)){file.write(JsonData);file.close();}

可以发现我们需要的数据在data-info-[编号]里边,因此我们要进到里边去读取数据

file
进入data-info-[序号],读取歌名,歌手名,hash,专辑,存入搜索数据表,并且把歌曲名和歌手名作为item展示在界面上

// 将 JSON 数据解析为 QJsonDocument 对象QJsonDocument document = QJsonDocument::fromJson(JsonData);if(document.isObject()) // 如果解析后的对象是一个 JSON 对象{QJsonObject data = document.object(); // 获取 JSON 对象中的"data"字段if(data.contains("data")) // 如果"data"字段存在{QJsonObject objectInfo = data.value("data").toObject(); // 获取"data"字段中的对象if(objectInfo.contains("info")) // 如果"info"字段存在{QJsonArray objectHash = objectInfo.value("info").toArray(); // 获取"info"字段中的数组for(int i = 0; i < objectHash.count(); i++) // 遍历数组中的每个元素{QString songname, singername, album_id, hash;QJsonObject album = objectHash.at(i).toObject(); // 获取数组元素中的对象// 从对象中获取歌曲名、歌手名、专辑 ID 和哈希值if(album.contains("album_id")){album_id = album.value("album_id").toString();}if(album.contains("songname")){songname = album.value("songname").toString();}if(album.contains("singername")){singername = album.value("singername").toString();}if(album.contains("hash")){hash = album.value("hash").toString();}// 将解析出的信息插入数据库QSqlQuery query;QString sql = QString("insert into songlist values(%1,'%2','%3','%4','%5')").arg(QString::number(i)).arg(songname).arg(singername).arg(album_id).arg(hash);if(!query.exec(sql)) // 如果插入数据库失败{QMessageBox::critical(nullptr, "插入数据库错误", db.lastError().text());}// 在搜索展示框中显示歌曲名称和歌手名称QString show = songname + "  " + singername;QListWidgetItem *item = new QListWidgetItem(show);ui->lw_search->addItem(item);}}}}

运行程序搜索后发现报错,插入数据库报错,查看发现数据库只有4个title,而我插入有5个,少了个hash,修改前边代码,添加上hash表头
file
再次运行发现不报错,也可以显示信息了

4 歌曲下载播放,修改新的酷狗搜索下载api

4.1 歌曲下载和播放downloadPlayer

构建下载歌曲的url,发起http请求,等待完成并获取数据,musicJsonAnalysis解析Json获取要播放的文件url

// 音乐歌曲的下载和播放
void OnlineMp3Widget::downloadPlayer(QString album_id, QString hash)
{// 构建下载歌曲的 URLQString url = kugouDownldadApi + QString("r=play/getdata""&hash=%1&album_id=%2""&dfid=1spkkh3QKS9PeiJupz0oTy5G""&mid=de94e92794f31e9cd6ff4cb309d2baa2""&platid=4").arg(hash).arg(album_id);// 发起 HTTP 请求获取歌曲数据httpAccess(url);QByteArray JsonData;QEventLoop loop;// 等待 HTTP 请求完成并获取数据auto d = connect(this, &OnlineMp3Widget::finish, [&](const QByteArray &data){JsonData = data;loop.exit(1);});loop.exec();disconnect(d);// 解析要播放的音乐QString music = musicJsonAnalysis(JsonData);// 设置媒体并播放音乐player->setMedia(QUrl(music));// 设置音量player->setVolume(50);// 设置音量滚动条ui->hs_sound->setValue(50);// 播放音乐player->play();
}

4.2 解析歌曲歌词json文件musicJsonAnalysis

首先也是先下载一下json看一下里边的格式,我们需要进入data字段获取lyrics和play_url。发送显示歌词信号,返回播放地址url

// 解析 JSON 数据,获取音乐播放 URL
QString OnlineMp3Widget::musicJsonAnalysis(QByteArray JsonData)
{// 保存 JSON 数据到文件中以便查看QFile file("download.json");if (file.open(QIODevice::WriteOnly | QIODevice::Text)){file.write(JsonData);file.close();}// 解析 JSON 数据QJsonDocument document = QJsonDocument::fromJson(JsonData);if (document.isObject()){QJsonObject data = document.object();if (data.contains("data")){QJsonObject objectPlayurl = data.value("data").toObject();// 如果包含歌词,发送歌词显示信号if (objectPlayurl.contains("lyrics")){emit lyricShow(objectPlayurl.value("lyrics").toString());}// 返回音乐播放 URLif (objectPlayurl.contains("play_url")){return objectPlayurl.value("play_url").toString();}}}
}

4.3 双击搜索列表歌曲播放playSearchMusic

双击搜索列表的歌曲,实现播放,先在构造函数里绑定槽函数,查询到QLIstWidegt有这样的一个点击信号,我们就使用它connect(ui->lw_search,&QListWidget::itemClicked,this,&OnlineMp3Widget::playSearchMusic);

file
点击尝试一下,可以输出行号

//获取双击的歌曲索引,就是数据库的数据表的ID号int row = ui->lw_search->currentRow();qDebug()<<"row"<<row;

file

随后我们先查询历史记录里有没有这首歌,没有就储存,插入新的数据,然后调用downloadPlayer下载播放歌曲

QSqlQuery query;QString sql = QString("select * from songlist where id = %1;").arg(row);if (!query.exec(sql)){QMessageBox::critical(nullptr, "select * from songlist where id =", db.lastError().text());}// 将选中的音乐的数据信息存入历史数据表QString songname, singername, album_id, hash;while (query.next()){QSqlRecord record = query.record();int songkey = record.indexOf("songname");int singerkey = record.indexOf("singername");int albumkey = record.indexOf("album_id");int hashkey = record.indexOf("hash");songname = query.value(songkey).toString();singername = query.value(singerkey).toString();album_id = query.value(albumkey).toString();hash = query.value(hashkey).toString();// 查询历史数据表中是否已经存在该歌曲的记录sql = QString("select hash from songhistory where hash = '%1'").arg(hash);if (!query.exec(sql)){QMessageBox::critical(nullptr, "select hash from songhistory where hash =", db.lastError().text());}// 如果不存在该记录,则将其存入历史数据表if (query.next() == NULL){sql = QString("insert into songhistory values(NULL, '%1', '%2', '%3', '%4')").arg(songname).arg(singername).arg(album_id).arg(hash);if (!query.exec(sql)){QMessageBox::critical(nullptr, "insert error", db.lastError().text());}// 将歌手和歌名放入历史歌曲表中显示QString show = songname + " " + singername;QListWidgetItem *item = new QListWidgetItem(show);ui->lw_record->addItem(item);}}// 下载并播放选中的音乐downloadPlayer(album_id, hash);

4.4 双击没有声音

但是此时运行双击歌曲,发现有报错,插入hash报错了。原来是我新建历史表格的数不对,表头只有歌名和歌手,所以插入报错了。修改后再次运行,双击无报错,但没有声音。
排查发现获取到的download的Json数据有问题,可能是api失效了。
file
发现歌词和播放地址现在都存在这里边
file
他的链接形式
https://wwwapi.kugou.com/play/songinfo?srcappid=2919&clientver=20000&clienttime=1713771570169&mid=707708a817d80eedd95f2ae68bc57780&uuid=707708a817d80eedd95f2ae68bc57780&dfid=11SITU3au0iw0OdGgJ0EhTvI&appid=1014&platid=4&encode_album_audio_id=j5yn384&token=&userid=0&signature=59068ffba4652d7eb4868a460db73375
对比两首不同得歌,这三个参数不一样,而且现在hash已经没用了,使用的是encode_album_audio_id
clienttime:时间戳
encode:音乐
signature:md5加密参数
file
主要是signature这个参数,找到他,打开代码来源
file
打上断点刷新页面运行几步代码,发现也就是这些信息组合后加密得到signature
file

4.4.1 安装openssl(可以不装,没用到)

要使用md5加密的库需要安装openssl,我们直接下载安装版https://slproweb.com/products/Win32OpenSSL.html,下载64位的安装包
file
这一步我们选择放到bin
file
打开cmd,输入openssl version,显示版本,安装成功
file

4.4.2 md5加密函数实现

就是把网页上的所有字符串都拼起来然后进行加密

QString OnlineMp3Widget::getMd5(QString time, QString encode_album_audio_id)
{// 构建签名列表QStringList signature_list;signature_list << "NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"<< "appid=1014"<< "clienttime=" + time<< "clientver=20000"<< "dfid=11SITU3au0iw0OdGgJ0EhTvI"<< "encode_album_audio_id=" + encode_album_audio_id<< "mid=707708a817d80eedd95f2ae68bc57780"<< "platid=4"<< "srcappid=2919"<< "token="<< "userid=0"<< "uuid=707708a817d80eedd95f2ae68bc57780"<< "NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt";// 将签名列表中的元素连接成一个字符串QString string = signature_list.join("");//qDebug()<< string;//生成 MD5 哈希QByteArray hashedData = QCryptographicHash::hash(string.toUtf8(), QCryptographicHash::Md5);// 将哈希数据转换为十六进制字符串QString md5Hash = hashedData.toHex();return md5Hash;
}

同时需要修改酷狗api

static QString kugouDownldadApi = "https://wwwapi.kugou.com/play/songinfo?";//构建下载歌曲的 URLQDateTime time = QDateTime::currentDateTime();// 将当前时间转换为自纪元以来的秒数,并将其转换为字符串QString currentTimeString = QString::number(time.toSecsSinceEpoch()*1000);currentTimeString = "1713782920612";QString encode_album_audio_id = "j5yn384";QString signaturecode = getMd5(currentTimeString,encode_album_audio_id);QString url = kugouDownldadApi + QString("srcappid=2919""&clientver=20000""&clienttime=%1""&mid=707708a817d80eedd95f2ae68bc57780""&uuid=707708a817d80eedd95f2ae68bc57780""&dfid=11SITU3au0iw0OdGgJ0EhTvI""&appid=1014""&platid=4""&encode_album_audio_id=%2""&token=""&userid=0""&signature=%3").arg(currentTimeString).arg(encode_album_audio_id).arg(signaturecode);

手动输入网页的时间和歌曲id,进行测试看看md5加密对不对,发现能够对上,并且也能够播放音乐了
file

4.5 hash已经没用了,替换为encode_album_audio_id,修改搜索歌曲函数

hash已经是老的apil,现在使用encode_album_audio_id即可,我们回到搜索歌曲的Json里,发现没有那个id,所以要自己重新搜索加入。在酷狗的搜索界面我们找到了这个id,把他取出。
file
对比发现更下载歌曲的变化相同,仿照着上边来写
file
file
更改酷狗搜索apihttps://complexsearch.kugou.com/v2/search/song?,修改搜索歌曲

//搜索歌曲
void OnlineMp3Widget::on_btn_search_clicked()
{// 清空搜索队列ui->lw_search->clear();// 清理数据库中已经存储的 hash 等数据QSqlQuery query;QString sql = "delete from songlist;" ;if(!query.exec(sql)){QMessageBox::critical(nullptr,"错误",query.lastError().text());}QDateTime time = QDateTime::currentDateTime();// 将当前时间转换为自纪元以来的秒数,并将其转换为字符串QString currentTimeString = QString::number(time.toSecsSinceEpoch()*1000);QString signaturecode = getSearch_Md5(ui->le_search->text(),currentTimeString);// 根据用户输入的 MP3 名称发起操作请求QString url = kugouSearchApi + QString("callback=callback123""&srcappid=2919""&clientver=1000""&clienttime=%1""&mid=707708a817d80eedd95f2ae68bc57780""&uuid=707708a817d80eedd95f2ae68bc57780""&dfid=11SITU3au0iw0OdGgJ0EhTvI""&keyword=%2""&page=1""&pagesize=30""&bitrate=0""&isfuzzy=0""&inputtype=0""&platform=WebFilter""&userid=0""&iscorrection=1""&privilege_filter=0""&filter=10""&token=""&appid=1014""&signature=%3").arg(currentTimeString).arg(ui->le_search->text()).arg(signaturecode);// 发起 HTTP 请求httpAccess(url);QByteArray JsonData;QEventLoop loop;// 等待 HTTP 请求完成并获取数据auto c = connect(this, &OnlineMp3Widget::finish, [&](const QByteArray &data){JsonData = data;loop.exit(1);});loop.exec();disconnect(c);// 解析获取的 JSON 数据hashJsonAnalysis(JsonData);
}

打断点跟上边一样,发现要输入这些数据,进行md5的编码
file

QString OnlineMp3Widget::getSearch_Md5(QString songname, QString time)
{// 构建签名列表QStringList signature_list;signature_list <<   "NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"<<   "appid=1014"<<   "bitrate=0"<<   "callback=callback123"<<   "clienttime=" + time<<   "clientver=1000"<<   "dfid=11SITU3au0iw0OdGgJ0EhTvI"<<   "filter=10"<<   "inputtype=0"<<   "iscorrection=1"<<   "isfuzzy=0"<<   "keyword=" + songname<<   "mid=707708a817d80eedd95f2ae68bc57780"<<   "page=1"<<   "pagesize=30"<<   "platform=WebFilter"<<   "privilege_filter=0"<<   "srcappid=2919"<<   "token="<<   "userid=0"<<   "uuid=707708a817d80eedd95f2ae68bc57780"<<   "NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt";// 将签名列表中的元素连接成一个字符串QString string = signature_list.join("");//qDebug()<< string;//生成 MD5 哈希QByteArray hashedData = QCryptographicHash::hash(string.toUtf8(), QCryptographicHash::Md5);// 将哈希数据转换为十六进制字符串QString md5Hash = hashedData.toHex();return md5Hash;
}

4.6 修改数据库和其他相关代码

先手动删除数据库中的两个表,修改搜索数据库(代码改动较多,可以查看提交)
file
修改完后运行,查看hashjson,拿到EMixSongID,要进入data-list-EMixSongID
file
修改代码,发现Json前边有callback123(),识别不了,需要把这个callback123和外边的一对括号删了,找到括号的下标,提取出中间的Json

//移除callback123()// 找到第一个左括号 "(" 的位置int leftBracketIndex = JsonData.indexOf('(');if (leftBracketIndex != -1){// 找到最后一个右括号 ")" 的位置int rightBracketIndex = JsonData.lastIndexOf(')');if (rightBracketIndex != -1){// 提取 JSON 数据,去除包裹的部分JsonData = JsonData.mid(leftBracketIndex + 1, rightBracketIndex - leftBracketIndex - 1);}}

修改下边读取Json,读取FileName,EMixSongID

// 将 JSON 数据解析为 QJsonDocument 对象QJsonDocument document = QJsonDocument::fromJson(JsonData);if(document.isObject()) // 如果解析后的对象是一个 JSON 对象{qDebug()<<"boject";QJsonObject data = document.object(); // 获取 JSON 对象中的"data"字段if(data.contains("data")) // 如果"data"字段存在{QJsonObject objectInfo = data.value("data").toObject(); // 获取"data"字段中的对象qDebug()<<"data";if(objectInfo.contains("lists")) // 如果"lists"字段存在{QJsonArray objectHash = objectInfo.value("lists").toArray(); // 获取"lists"字段中的数组qDebug()<<"lists";for(int i = 0; i < objectHash.count(); i++) // 遍历数组中的每个元素{QString singer_song_name,EMixSongID;QJsonObject album = objectHash.at(i).toObject(); // 获取数组元素中的对象// 从对象中获取歌曲名、歌手名、专辑 ID 和哈希值if(album.contains("FileName")){singer_song_name = album.value("FileName").toString();}if(album.contains("EMixSongID")){EMixSongID = album.value("EMixSongID").toString();}// 将解析出的信息插入数据库QSqlQuery query;QString sql = QString("insert into songlist values(%1,'%2','%3');").arg(QString::number(i)).arg(singer_song_name).arg(EMixSongID);if(!query.exec(sql)) // 如果插入数据库失败{QMessageBox::critical(nullptr, "插入数据库错误", db.lastError().text());}// 在搜索展示框中显示歌曲名称和歌手名称QListWidgetItem *item = new QListWidgetItem(singer_song_name);ui->lw_search->addItem(item);}}}}

再次运行,搜索列表能够显示歌曲

4.7 修复双击播放歌曲playSearchMusic

代码与新的数据库对应即可

// 将选中的音乐的数据信息存入历史数据表QString  singer_song_name,EMixSongID;while (query.next()){QSqlRecord record = query.record();int singer_song_namekey = record.indexOf("FileName");int EMixSongIDkey = record.indexOf("EMixSongID");singer_song_name = query.value(singer_song_namekey).toString();EMixSongID = query.value(EMixSongIDkey).toString();// 查询历史数据表中是否已经存在该歌曲的记录sql = QString("select EMixSongID from songhistory where EMixSongID = '%1';").arg(EMixSongID);if (!query.exec(sql)){QMessageBox::critical(nullptr, "select hash from songhistory where EMixSongID =", db.lastError().text());}// 如果不存在该记录,则将其存入历史数据表if (query.next() == NULL){sql = QString("insert into songhistory values(NULL, '%1', '%2')").arg(singer_song_name).arg(EMixSongID);if (!query.exec(sql)){QMessageBox::critical(nullptr, "insert error", db.lastError().text());}// 将歌手和歌名放入历史歌曲表中显示QListWidgetItem *item = new QListWidgetItem(singer_song_name);ui->lw_record->addItem(item);}}// 下载并播放选中的音乐downloadPlayer(EMixSongID);
}

5 歌词显示,进度条

5.1 歌词显示

点击访问博客查看更多内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/641875.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试算法准备:动态规划

这里写自定义目录标题 1 理论2 例题2.1 斐波那契数列&#xff08;什么是重叠子问题&#xff09;2.1.1 带备忘录的递归解法 2.2 零钱兑换&#xff08;讲解最优子结构&#xff09;2.3 最长递增子序列&#xff08;讲解如何求解状态转移方程&#xff09;2.4 俄罗斯套娃信封问题&…

刷课必备!用Python实现网上自动做题

前言 开学少不了老师会布置一些 软件上面的作业&#xff0c;今天教大家用python制作自动答题脚本&#xff0c;100%准确率哦喜欢的同学记得关注、收藏哦 环境使用 Python3.8Pycharm 模块使用 import requests —> 数据请求模块 pip install requestsimport parsel —>…

鸿蒙开发模拟器的坑, No Devices

问题 我已经安装了模拟器&#xff0c;并且模拟器已经运行了 在Device Manager页面开启模拟器 No Devices 但是这里没有模拟器的选项 解决 添加环境变量 下面步骤 1、清除用户数据 2、 关闭Device Manager 3、 关闭ide 重启ide、开启模拟器 看到有模拟器的选项了

windows系统CUDA的详细安装教程

CUDA系列 文章目录 CUDA系列前言一、CUDA简介二、安装配置视频教程三、CUDA的下载及安装3.1 环境检查3.2 CUDA 安装包下载3.3 安装CUDA&#xff08;略&#xff09;3.4 验证CUDA是否安装成功 四、cuDNN的下载及安装4.1 cuDNN下载4.2 cuDNN配置 五、配置环境变量六、下载并配置zl…

探索 去中心化的Web3.0

随着区块链技术的日益成熟和普及&#xff0c;Web3&#xff08;Web 3.0&#xff09;已经成为一个无法忽视的趋势。Web3不仅仅是一个技术概念&#xff0c;更是一个去中心化、透明、用户数据拥有权归还给用户的互联网新时代。在这篇文章中&#xff0c;我们将深入探讨Web3技术的核心…

LoggerFactory is not a Logback

错误信息 LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.SimpleLoggerFactory loaded from file:/D:/maven/repository/org/slf4j/slf4j-simple/1.7.26/slf…

AI检索增强生成引擎-RAGFlow-深度理解知识文档,提取真知灼见

&#x1f4a1; RAGFlow 是什么&#xff1f; RAGFlow是一款基于深度文档理解构建的开源RAG&#xff08;Retrieval-Augmented Generation&#xff09;引擎。RAGFlow个人可以为各种规模的企业及提供一套专业的RAG工作流程&#xff0c;结合针对用户群体的大语言模型&#xff08;LL…

linux负载均衡 和 系统负载分析笔记

1 负载均衡 1.1 计算负载 1.1.1 PELT算法简介 从Linux3.8内核以后进程的负载计算不仅考虑权重&#xff0c;⽽且跟踪每个调度实体的历史负载情况&#xff0c;该算法称为PELT(Per-entity Load Tracking) 《奔跑吧Linux内核》卷1&#xff1a;基础架构&#xff1b;P505 相关资料…

软件测试架构体系之软件测试基本流程图

前言&#xff1a; 采用通用的测试流程&#xff0c;能高效、高质量的完成软件测试工作&#xff0c;有助于减少沟通成本&#xff0c;对各阶段产出有明确认知等等。最终目标&#xff1a;实现软件测试规范化、标准化。以下为非通用标准&#xff0c;仅供大家参考。 一、软件测试流…

unity 录制360全景渲染图

1.打开pakcageManager &#xff0c;选择packages为 unityRegisty&#xff0c;找到unityRecorder插件下载&#xff0c;点击右下角instant安装&#xff0c;如果插件列表为空&#xff0c;检查是否连接网络&#xff0c;重启Unity 2.打开录制面板 3.add recorder 选择ImageSequence …

【WEB前端2024】开源元宇宙:乔布斯3D纪念馆-第9课-摆件美化

【WEB前端2024】开源元宇宙&#xff1a;乔布斯3D纪念馆-第9课-摆件美化 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎&#…