前言
因为放寒假了,时间比较短,想找实习也不好找,干脆在家加强一下技术栈,首先从c++学起,最适合练手的就是qt的项目了,我是根据B站视频【5个C/C++硬核简历项目实战,可直接写入简历,包含:Qt项目、音视频流媒体开发、后端开发、DPDK网络编程、KV存储、Linux内核。总有一个实战项目适合你!】来进行学习的,这篇文章主要是记录一下在跟视频做的过程中,自己的学习体会和问题的解决思路。
项目已上传至Github:https://github.com/MengFanjun020906/OnlineMusic
1.主窗口添加功能
1.1 进度条控件美化
// 播放进度条控件美化
ui->horizontalSlider_PlayProgress->setStyleSheet("QSlider::groove:horizontal {"
" border: 1px solid #bbb;"
" background: white;"
" height: 10px;"
" border-radius: 5px;"
"}"
"QSlider::sub-page:horizontal {"
" background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #66e, stop: 1 #bbf);"
" border: 1px solid #777;"
" height: 10px;"
" border-radius: 5px;"
"}"
"QSlider::add-page:horizontal {"
" background: #fff;"
" border: 1px solid #777;"
" height: 10px;"
" border-radius: 5px;"
"}"
"QSlider::handle:horizontal {"
" background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc);"
" border: 1px solid #777;"
" width: 18px;"
" margin-top: -4px;"
" margin-bottom: -4px;"
" border-radius: 9px;"
"}");
ui->horizontalSlider_Volume->setStyleSheet("QSlider::groove:horizontal {"
" border: 1px solid #bbb;"
" background: white;"
" height: 10px;"
" border-radius: 5px;"
"}"
"QSlider::sub-page:horizontal {"
" background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #66e, stop: 1 #bbf);"
" border: 1px solid #777;"
" height: 10px;"
" border-radius: 5px;"
"}"
"QSlider::add-page:horizontal {"
" background: #fff;"
" border: 1px solid #777;"
" height: 10px;"
" border-radius: 5px;"
"}"
"QSlider::handle:horizontal {"
" background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc);"
" border: 1px solid #777;"
" width: 18px;"
" margin-top: -4px;"
" margin-bottom: -4px;"
" border-radius: 9px;"
"}");
实现的效果如下,虽然也不是特别好看,但是效果比原来的好看得多。
1.2 初始化多媒体实例
因为qt6的MediaPlayList被移除了,所以需要我们自己写playlist的相关函数和头文件,但如果是qt5的话,这个类就可以正常使用
//将光标焦点定位到搜索歌曲名称的控件
ui->lineEdit_InputSong->setFocus();
//初始化
NetworkAccessManager = new QNetworkAccessManager(this);
iPos=0;
//初始文本对象
docTextObject = ui->plainTextEdit_SongList->document();
//将控件设置为只读
ui->plainTextEdit_SongList->setReadOnly(true);
//初始化多媒体实例
p_PlayerObject=new QMediaPlayer(this);
//p_PlayerList = new
Playlist *p_PlayList = new Playlist(this);
//设置播放模式
p_PlayList->setPlaybackMode(Playlist::Loop);
//信号与槽处理如下
connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandleLCDNumberTimeChangeFunc(qint64)));
connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandlePositionChangeFunc(qint64)));
connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandleProgressTimeChangeFunc(qint64)));
connect(NetworkAccessManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(HandleDataBackFunc(QNetworkReply*)));
2.搜索歌曲显示歌手功能
这个函数是 OnlineMusicWidget 类的一个槽函数,它会在 pushButton_SearchSong 按钮被点击时触发。其主要功能是根据用户在 lineEdit_InputSong 输入框中输入的歌曲名称,向网易云音乐的搜索 API 发送一个 GET 请求,以获取相关歌曲的搜索结果。
void OnlineMusicWidget::HandleDataBackFunc(QNetworkReply *pReply)
{
//读取网络回款数据
QByteArySearchInfo = pReply->readAll();
QJsonParseError JSonPError;//定义错误信息对象
//将json文本转换为json文件对象
QJsonDocument JSonDoc_RecvData=QJsonDocument::fromJson(QByteArySearchInfo,&JSonPError);
if(JSonPError.error!=QJsonParseError::NoError)//判断是否符合规则
{
QMessageBox::critical(this,"Prompt","提示:获取歌曲json出错,请重新检查",QMessageBox::Yes);
return;
}
//QJsonObject使用函数object();
QJsonObject TotalJsonObject = JSonDoc_RecvData.object();
//列出json里面的所有key
QStringList strKeys=TotalJsonObject.keys();
if(strKeys.contains("result"))//与数据信息
{
//将带有result的数据内容提取之后转换为对象
QJsonObject resultobject=TotalJsonObject["result"].toObject();
//存储所有keys
QStringList strResultKeys=resultobject.keys();
if(strResultKeys.contains("songs"))
{
QJsonArray array=resultobject["songs"].toArray();
//通过for循环查找歌曲当中的字段信息
for(auto isong:array)
{
QJsonObject jsonobject1 = isong.toObject();
//获取歌曲ID 歌名 歌手
I_MusicID = jsonobject1["id"].toInt();
StrMusicName = jsonobject1["name"].toString();
QStringList strkeys = jsonobject1.keys();
if(strkeys.contains("artists"))
{
QJsonArray artitstsjsonarray= jsonobject1["artists"].toArray();
for(auto js:artitstsjsonarray)
{
QJsonObject jsonobject2=js.toObject();
StrSingerName = jsonobject2["name"].toString();
}
}
}
}
}
// 生成歌曲 URL
QString url = QString("https://music.163.com/song/media/outer/url?id=%0").arg(I_MusicID);
// 创建一个 QVariantMap 并将歌曲 URL 存储在 "path" 键下
QVariantMap song;
song["path"] = url;
// 调用 appendSong 函数将歌曲添加到播放列表
p_PlayList->appendSong(song);
ui->plainTextEdit_SongList->appendPlainText(StrMusicName+"-"+StrSingerName);
}
//搜索歌曲名称实现
void OnlineMusicWidget::on_pushButton_SearchSong_clicked()
{
QString str1,str2;
str1=ui->lineEdit_InputSong->text();
str2="http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={"+str1+"}&type=1&offset=0&total=true&limit=1";
//定义一个请求对象
QNetworkRequest networkRequest;
networkRequest.setUrl(str2);
//将请求格式设置给对应请求对象
networkRequest.setUrl(str2);
//使用QNetworkAccessManager类对应的API发送GET请求并获取响应数据
NetworkAccessManager->get(networkRequest);
}
3.播放功能
3.1 播放按钮播放
从回传的id去获取歌曲的url,但是需要注意的是,VIP歌曲不能播放,网易云的网页版和APP版还不一样,网页版连试听都没有,我再搜岁歌曲的时候,发现怎么着都播放不出来,选几首比较冷门的歌,才发现原来问题是没有开vip。
//播放歌曲
void OnlineMusicWidget::on_pushButton_PlaySong_clicked()
{
qDebug() << "播放列表内容:" << playList;
qDebug() << "当前播放索引:" << currentIndex;
qDebug() << "播放器状态:" << p_PlayerObject->playbackState();
qDebug() << "[Debug] 当前播放器状态:" << p_PlayerObject->playbackState();
// 1. 处理空播放列表
if (playList.isEmpty()) {
QMessageBox::warning(this, "错误", "播放列表为空");
return;
}
// 2. 自动定位到第一首
if (currentIndex == -1) {
currentIndex = 0;
}
// 3. 核心逻辑
switch (p_PlayerObject->playbackState()) {
case QMediaPlayer::StoppedState: // 停止状态
case QMediaPlayer::PausedState: // 暂停状态
// 只有源文件变化时才重新设置
if (p_PlayerObject->source() != playList[currentIndex]) {
p_PlayerObject->setSource(playList[currentIndex]);
}
p_PlayerObject->play();
//ui->pushButton_PlaySong->setText("暂停");
break;
case QMediaPlayer::PlayingState: // 正在播放
p_PlayerObject->pause();
//ui->pushButton_PlaySong->setText("播放");
break;
default: // 无媒体或错误状态
p_PlayerObject->setSource(playList[currentIndex]);
p_PlayerObject->play();
//ui->pushButton_PlaySong->setText("暂停");
break;
}
}
3.2 暂停与停止功能
这里直接调用PlayerObject的函数即可
//暂停播放
void OnlineMusicWidget::on_pushButton_PauseSong_clicked()
{
// 只有正在播放时才能暂停
if (p_PlayerObject->playbackState() == QMediaPlayer::PlayingState) {
p_PlayerObject->pause();
//ui->pushButton_PlaySong->setText("播放"); // 同步更新播放按钮状态
qDebug() << "音乐已暂停";
}
}
//停止播放
void OnlineMusicWidget::on_pushButton_StopPlaySong_clicked()
{
if (p_PlayerObject->playbackState() != QMediaPlayer::StoppedState) {
p_PlayerObject->stop();
//ui->pushButton_PlaySong->setText("播放"); // 强制更新播放按钮状态
qDebug() << "音乐已停止";
}
}
3.3 上一曲与下一曲的切换
//播放上一曲
void OnlineMusicWidget::on_pushButton_PreviousSong_clicked()
{
if (playList.isEmpty()) {
QMessageBox::warning(this, "提示", "播放列表为空");
return;
}
// 计算新索引(支持循环)
currentIndex = (currentIndex - 1 + playList.size()) % playList.size();
// 设置新播放源
p_PlayerObject->setSource(playList[currentIndex]);
// 自动开始播放
p_PlayerObject->play();
qDebug() << "上一曲";
}
//播放下一曲
void OnlineMusicWidget::on_pushButton_NextSong_2_clicked()
{
if (playList.isEmpty()) {
QMessageBox::warning(this, "提示", "播放列表为空");
return;
}
// 计算新索引(支持循环)
currentIndex = (currentIndex + 1) % playList.size();
// 设置新播放源
p_PlayerObject->setSource(playList[currentIndex]);
// 自动开始播放
p_PlayerObject->play();
qDebug() << "下一曲";
}
4.音量控制
静音实现
void OnlineMusicWidget::on_pushButton_SoundYesNo_clicked()
{
QAudioOutput* audioOutput = p_PlayerObject->audioOutput();
if (isMuted) {
// 取消静音,恢复之前音量
audioOutput->setMuted(false);
audioOutput->setVolume(previousVolume);
ui->horizontalSlider_Volume->setValue(previousVolume * 100);
ui->pushButton_SoundYesNo->setIcon(QIcon(":/new/prefix1/Images/MSound.png"));
qDebug() << "取消静音,恢复音量到:" << previousVolume;
} else {
// 记录当前音量并静音
previousVolume = audioOutput->volume();
audioOutput->setMuted(true);
ui->pushButton_SoundYesNo->setIcon(QIcon(":/new/prefix1/Images/MNoSound.png"));
qDebug() << "静音,原音量:" << previousVolume;
}
isMuted = !isMuted; // 切换状态
}
拖动滑块改变歌曲音量
//音量控制
void OnlineMusicWidget::on_horizontalSlider_Volume_valueChanged(int value)
{
QAudioOutput* audioOutput = p_PlayerObject->audioOutput();
// 将滑块值(0-100)转换为浮点音量(0.0-1.0)
qreal volume = qBound(0.0, value / 100.0, 1.0);
audioOutput->setVolume(volume);
// 同步静音状态
if (volume > 0 && audioOutput->isMuted()) {
audioOutput->setMuted(false);
ui->pushButton_SoundYesNo->setIcon(QIcon(":/new/prefix1/Images/MSound.png"));
isMuted = false;
}
}
5.歌曲时间显示
在进度条右侧的LCD数字会显示歌曲的时长
//处理LCD控件时间变化
void OnlineMusicWidget::HandleLCDNumberTimeChangeFunc(qint64 duration)
{
int int_Second=duration/1000;
int int_Minute=int_Second/60;
int_Second=int_Second%60;
QString strSongTime=QString::asprintf("%d:%d",int_Minute,int_Second);
ui->lcdNumber_PlayTime->display(strSongTime);
}
歌曲的进度条会随着播放而变化
// 处理进度条控件变化
void OnlineMusicWidget::HandleProgressTimeChangeFunc(qint64 duration)
{
//设置进度条最大值
ui->horizontalSlider_PlayProgress->setMaximum(duration);
}