基于Qt的在线音乐播放器
项目功能:
本在线音乐播放器的功能在于创建一个音乐播放器页面,可以实现搜索功能通过HTTP协议获取网络中数据并解析出来,播放搜索到的歌曲并展示相关信息。效果如图:
相关类及功能
- Musicinterface 视图类;
主要功能:初始化窗口;设置按钮功能和窗口内容的显示; - HttpHandle 网络连接类;
主要功能:连接网络、发送请求、接收数据、用JSON解析数据; - MusicPlayer 音乐播放类;
主要功能:播放音乐、修正歌词; - GraphicsView 动画展示类;
主要功能:在窗口显示专辑图片,让唱片随音乐播放转动,音乐停止而停止;唱针随音乐播放拨动到唱片上,音乐停止归位;
Musicinterface 视图类
初始化歌曲列表窗口
void Musicinterface::initTableWidget()
{
ui->tableWidget_musicList->setStyleSheet("selection-background-color:pink; selection-color: white;"); //设置tableWidget QSS样式表,背景为红色,字体为白色
ui->tableWidget_musicList->hideColumn(0); //隐藏第一列
ui->tableWidget_musicList->hideColumn(1); //隐藏第2列
ui->tableWidget_musicList->setEditTriggers(QAbstractItemView::NoEditTriggers); //设置不可编辑
ui->tableWidget_musicList->setSelectionBehavior(QAbstractItemView::SelectRows);//一次选一行
ui->tableWidget_musicList->setFocusPolicy(Qt::NoFocus); //去掉虚线框
ui->tableWidget_musicList->setSortingEnabled(true); //增加表头排序功能
ui->tableWidget_musicList->horizontalHeader()->setFixedHeight(30); //固定列头高度为30像素
ui->tableWidget_musicList->horizontalHeader()->setStyleSheet("QHeaderView::section{background:rgb(170,170,255);}"); //设置tableWidget列头QSS样式表,背景为天蓝
ui->tableWidget_musicList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//表头拉伸
ui->tableWidget_musicList->horizontalHeader()->setHighlightSections(false); //选中列头不在高亮
ui->tableWidget_musicList->verticalHeader()->hide();//隐藏行头
ui->tableWidget_musicList->verticalHeader()->setHighlightSections(false); //选中行头不在高亮
}
初始化歌词窗口
void Musicinterface::initTextEdit()
{
QPalette palette = ui->textEdit_musicWord->palette(); //获取textEdit的调色板
palette.setColor(QPalette::Highlight, QColor(Qt::transparent)); //将选中区域背景改为透明
palette.setColor(QPalette::HighlightedText, QColor(Qt::red)); //将选中区域的文字改为红色
ui->textEdit_musicWord->setPalette(palette); //将调色板设置到textEdit
ui->textEdit_musicWord->setReadOnly(true); //设置为只读
ui->textEdit_musicWord->document()->setDefaultTextOption(QTextOption(Qt::AlignHCenter)); //文字居中显示
}
Qss
界面美化也可以用Qss实现
- 什么是Qss:Qt样式表,他是Qt提供的一种用来自定义控件外观的机制。
- 控件的构成:
1)Margin:控件最外围的透明区域,总为透明;
2)Border:控件最外围的边框;
3)Padding:控件的外边框内显示区域的空白区;
4)Content:控件最内显示区; - 语法规则
示例:
border-color: rgb(255, 170, 255);
border-radius:5px;
color: rgb(170, 0, 255);
QLineEdit
{
/*边界1像素 实线 颜色rgb 或者border:none 没有边界*/
border:1px solid rgb(180, 180, 180);
//背景的颜色
background: rgb(230,230,230);
//边角4像素圆滑
border-radius: 24px;
}
/*鼠标滑动到LineEditor上面的时候*/
QLineEdit::hover
{
//字体的颜色
color:green
border-color:rgb(50,480,40);
background-color:green;
}
1)选择器:如果不设置选择器,可能会对全局所有同类型的控件生效;此项目中常用ID选择器:#myButton匹配所有ID为“myButton”的控件,ID实际上是该控件的ObjectName;
#pushButton_playNext//ID
{
border-image: url(:/Image/next1.png);
}
2)背景属性:background 一次可以设置多个属性,用空格隔开background:<color> <image> <position> <repeat>
;也可以分开设置border-image: url(:/Image/next1.png);background-color: rgb(170, 170, 255);
3) 边框属性:border 一次可以设置多个属性,用空格隔开;/*边界1像素 实线 颜色rgb 或者border:none 没有边界*/ border:1px solid rgb(180, 180, 180);
color边框颜色、style边框风格、image控件图片、radius设置圆角;
4)字体属性:可以直接在选择字体对话框或者属性栏填写;
5)文本属性:color:设置文本颜色;text-align:设置文本对齐方式;text-transform: 设置文本大小写;word-spacing:设置单词间距离;
- 伪状态
hover: 鼠标悬停在指定控件时所使用的样式;
pressed: 控件被鼠标按下时的样式;
checked:控件被选中时的样式;
unchecked:控件未被选中时的样式;
示例:
#pushButton_playLast:pressed//被按下时的状态
{
border-image: url(:/Image/last2.png);
}
搜索歌曲
//歌曲列表
void Musicinterface::on_lineEdit_search_returnPressed()
{
ui->tableWidget_musicList->clearContents(); //清除表内所有数据(不包含表头数据和设置的其他属性)
ui->tableWidget_musicList->setRowCount(0); //设置当前行数,为0
QString searchData = ui->lineEdit_search->text();//获取输入搜索框的内容
httpHandle->searchMusicList(searchData);//搜索歌曲列表
}
按钮功能设置
将按钮右键转到槽并实现该函数;文章来源:https://www.toymoban.com/news/detail-436972.html
- 双击播放歌曲设置
//双击歌曲播放
void Musicinterface::on_tableWidget_musicList_cellDoubleClicked(int row, int column)
{
Q_UNUSED(column)
QString musicId = ui->tableWidget_musicList->item(row,0)->text();//获取row行0列数据
QString musicPicId = ui->tableWidget_musicList->item(row,1)->text();//row行0列
QString musicUrl = httpHandle->searchMusicUrl(musicId);//获取歌曲播放网址
QString lyric = httpHandle->searchMusicLyric(musicId);//获取歌词
QString picUrl = httpHandle->searchMusicPicUrl(musicPicId);//查找图片地址
picUrl.replace("300y300","1200y1200");//放大图片
QByteArray picData = httpHandle->getSearch(picUrl);
QImage pic = QImage::fromData(picData);
ui->graphicsView->reflushMusicPic(pic);//展示专辑图片
ui->textEdit_musicWord->setText(musicPlayer->parsingLyrics(lyric));//显示歌词
musicPlayer->setMedia(QUrl(musicUrl));//获取图片
musicPlayer->play();//播放音乐
ui->graphicsView->animationStart();//播放动画
}
- 播放与暂停按钮设置:声明一个槽函数,当音乐播放状态发生改变时,触发槽函数改变当前图标状态,在按钮转到槽函数中实现两种音乐播放状态的改变;
//音乐播放状态改变与暂停播放按钮状态
connect(musicPlayer,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(slotReflushPlayButtonIcon(QMediaPlayer::State)));
//播放、停止按钮的设计
void Musicinterface::slotReflushPlayButtonIcon(QMediaPlayer::State state)
{
if (state == QMediaPlayer::PlayingState)
{
ui->pushButton_musicPlay->setStyleSheet("#pushButton_musicPlay\
{\
border-image: url(:/Image/pause1.png); }\
#pushButton_musicPlay:pressed\
{\
border-image: url(:/Image/pause2.png);\
}");
}
else
{
ui->pushButton_musicPlay->setStyleSheet("#pushButton_musicPlay\
{\
border-image: url(:/Image/play1.png); }\
#pushButton_musicPlay:pressed\
{\
border-image: url(:/Image/play2.png);\
}");
}
}
//暂停与播放
void Musicinterface::on_pushButton_musicPlay_clicked()
{
int row = ui->tableWidget_musicList->currentRow(); //获取当前选中行
//获取当前播放状态
//播放或暂停
if (musicPlayer->state() == QMediaPlayer::PlayingState)
{
musicPlayer->pause();
ui->graphicsView->animationEnd();
}
else if (musicPlayer->state() == QMediaPlayer::PausedState)
{
int row2 = ui->tableWidget_musicList->currentRow(); //获取当前选中行
if (row == row2)//如果此时选中行与暂停前一样
{
ui->graphicsView->animationStart();
musicPlayer->play();
}
else
{
on_tableWidget_musicList_cellDoubleClicked(row2,0);
}
}
else //如果都不是,就播放当前选中的歌,如果没有选中就退出
{
int row = ui->tableWidget_musicList->currentRow(); //获取当前选中行
//如果没有选中就直接退出
if (row == -1)
{
return ;
}
else
{
on_tableWidget_musicList_cellDoubleClicked(row,0);
}
}
}
- 上一曲、下一曲切换设置(包括按键状态切换和歌曲切换,这里只写歌曲切换代码)
//上一曲
void Musicinterface::on_pushButton_playLast_clicked()
{
//获取当前选中行
int row = ui->tableWidget_musicList->currentRow(); //获取当前选中行
//如果没有选中就直接退出
if (row == -1)
{
return ;
}
//获取上一行的行号,如果是第一行,则获取最后一行
int endRow = ui->tableWidget_musicList->rowCount(); //获取当前共有多少行
if (row == 0)
{
row = endRow - 1;
}
else
row--;
//播放歌曲
on_tableWidget_musicList_cellDoubleClicked(row,0);//调用双击播放函数
//选中上一行
ui->tableWidget_musicList->selectRow(row); //选中第line行
}
- 随机播放与顺序播放设置:当一首音乐播完时,触发播放顺序函数,查看当前标志位状态并播放下一首歌曲;
//链接音乐播放状态与循环顺序按钮
connect(musicPlayer,SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),this,SLOT(slotPlay(QMediaPlayer::MediaStatus)));
//随机播放和顺序播放
void Musicinterface::slotPlay(QMediaPlayer::MediaStatus state)
{
if (state == QMediaPlayer::EndOfMedia)
{
if (playOrder)
{
on_pushButton_playNext_clicked();
}
else
{
int row = ui->tableWidget_musicList->rowCount(); //获取当前共有多少行
int n = qrand() % row;
on_tableWidget_musicList_cellDoubleClicked(n, 0);
ui->tableWidget_musicList->selectRow(row); //选中第line行
}
}
else if (state == QMediaPlayer::InvalidMedia)
{
QMessageBox msgBox;
msgBox.setWindowIcon(QIcon(":/Image/icon1.png"));
msgBox.setWindowTitle("CloudMusic");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText("Do ont have Sources");
msgBox.setInformativeText("Next Song");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
int ret = msgBox.exec();
if (ret == QMessageBox::Yes)
{
on_pushButton_playNext_clicked();
}
}
}
//随机数生成
QTime time;
time = QTime::currentTime();
qsrand(time.msecsSinceStartOfDay());
int row = ui->tableWidget_musicList->rowCount(); //获取当前共有多少行
int n = qrand() % row;
- 进度条设置
//歌曲时长
void Musicinterface::slotReflushEndTime(qint64 ms)//时长
{
ui->horizontalSlider_progressBar->setMaximum(ms);//进度条设置
QTime time = QTime::fromMSecsSinceStartOfDay(ms);
//显示总时长
ui->label_endTime->setText(time.toString("mm:ss"));//将ms 转化为分钟:秒
}
//歌曲当前时间
void Musicinterface::slotReflushStartTime(qint64 ms)//当前值
{
ui->horizontalSlider_progressBar->setValue(ms);//进度条设置
QTime time = QTime::fromMSecsSinceStartOfDay(ms);
//显示当前时长
ui->label_startTime->setText(time.toString("mm:ss"));//将ms 转化为分钟:秒
}
void Musicinterface::on_horizontalSlider_progressBar_sliderMoved(int position)
{
musicPlayer->setPosition(position);//进度条可拖动
}
- 歌词滚动展示 : 从网络中解析出来的歌词上带有时间;
//歌词滚动
void Musicinterface::slotLyricChange(int line)
{
QTextCursor tc2 = ui->textEdit_musicWord->textCursor();//获取当前光标
int pos2 = ui->textEdit_musicWord->document()->findBlockByLineNumber(line).position();//在textEdit中找到指定行位置
tc2.setPosition(pos2, QTextCursor::MoveAnchor); //将光标设置到指定位置
tc2.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);//光标设置成选中一整行,并且保持此状态
ui->textEdit_musicWord->setTextCursor(tc2);//将设置好的光标属性放到textEdit中
}
HttpHandle 网络连接类
- Qt 实现HTTP协议:HTTP协议数据格式为:请求行、头部行、和附属体;请求数据的方式共有七种,常用的有Get和Post两种;
- 常用的类有:
1)QNetworkRequest 网络连接请求类
2)QNetworkAccessManager 网络访问管理器,使应用程序发送网络请求并接收响应
3)QNetworkReply 网络回复类 接收网络数据 - Get方法时默认的HTTP请求方法,是将请求信息作为URL的一部分发送给Web服务器,存在安全隐患,而且有的服务器可能对URL的数据长度有限制;
QByteArray HttpHandle::getSearch(const QString &url)
{
QNetworkRequest networkRequest(url);//网址
QEventLoop eventloop;//事件循环
QNetworkReply *networkReply = networkAccessManager->get(networkRequest);
connect(networkReply,SIGNAL(finished()),&eventloop,SLOT(quit()));//接收信息结束,事件循环停止
eventloop.exec(QEventLoop::ExcludeUserInputEvents);//阻止未接收完第一次信息时的第二次搜索
return networkReply->readAll();
}
- Post方法是在向Web服务器提交表单数据时,将请求部分放在附属体中发送给服务器;
//将Url,头信息、请求方式封装成函数
//返回值是从网站接收到的数据
QByteArray HttpHandle::postSearch(const QString body)
{
QNetworkRequest networkRequest(QUrl("https://l-by.cn/yinyue/api.php"));//网址
networkRequest.setRawHeader(QByteArray("Content-Type"),QByteArray("application/x-www-form-urlencoded; charset=UTF-8"));//Head
QEventLoop eventloop;//事件循环
QNetworkReply *networkReply = networkAccessManager->post(networkRequest,body.toUtf8());
connect(networkReply,SIGNAL(finished()),&eventloop,SLOT(quit()));//接收信息结束,事件循环停止
eventloop.exec(QEventLoop::ExcludeUserInputEvents);//阻止未接收完第一次信息时的第二次搜索
return networkReply->readAll();
}
- JSON解析数据
1)QJsonParseError 用于json解析期间报错
2)QJsonDocument 用于写入或读取json文档数据
3)QJsonObject 封装了一个json类型对象,可用来获取json对象里的值
示例:
//搜索框查询函数,歌曲列表
void HttpHandle::searchMusicList(const QString &searchData)
{
//拼接字符串.arg()
QString body = QString("types=search&count=30&source=netease&pages=1&name=%1").arg(searchData);
QByteArray musicData = postSearch(body);//将Url,头信息、请求方式封装成函数调用
QJsonParseError error;//错误码
QJsonDocument jsonDocument = QJsonDocument::fromJson(musicData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音乐列表JSON数据失败!错误码:" << error.errorString();
return ;
}
//解析
QJsonArray musicInfoArray = jsonDocument.array();//大数组
for (int i = 0; i < musicInfoArray.size(); ++i)//遍历
{
QJsonObject musicObject = musicInfoArray[i].toObject();//对象
QStringList musicInfo;//字符串
QString id = QString::number(musicObject["id"].toInt());//解析id
QString picId = musicObject["pic_id"].toString();//解析pic_id (字符串类型)
QString name = musicObject["name"].toString();//解析歌名
QJsonArray artistArray = musicObject["artist"].toArray();//解析歌手(多人)
QString artist;
for (int j = 0; j < artistArray.size(); ++j)//遍历歌手
{
artist = artist + artistArray[j].toString() + ",";//拼接在一起XX,XX,XX
}
artist.chop(1);//删除最后一个“,”
QString album = musicObject["album"].toString();//解析专辑
musicInfo << id << picId << name << artist << album;//将所有解析到的信息拼在一起
emit signalShowMusicInfoList(musicInfo);//发送信号和信息给
}
}
//歌曲播放网址
QString HttpHandle::searchMusicUrl(const QString &id)
{
//拼接字符串.arg()
QString body = QString(" types=url&id=%1&source=netease").arg(id);
QByteArray musicData = postSearch(body);//将Url,头信息、请求方式封装成函数调用
QJsonParseError error;//错误码
QJsonDocument jsonDocument = QJsonDocument::fromJson(musicData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音乐地址JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject jsonobject = jsonDocument.object();
return jsonobject["url"].toString();
}
//歌词
QString HttpHandle::searchMusicLyric(const QString &id)
{
//拼接字符串.arg()
QString body = QString("types=lyric&id=%1&source=netease").arg(id);
QByteArray musicData = postSearch(body);//将Url,头信息、请求方式封装成函数调用
QJsonParseError error;//错误码
QJsonDocument jsonDocument = QJsonDocument::fromJson(musicData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音乐歌词JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject jsonobject = jsonDocument.object();
QString musiclyric = jsonobject["lyric"].toString();
return musiclyric;
}
//专辑图片
QString HttpHandle::searchMusicPicUrl(const QString &picId)
{
//拼接字符串.arg()
QString body = QString(" types=pic&id=%1&source=netease").arg(picId);
QByteArray picData = postSearch(body);//将Url,头信息、请求方式封装成函数调用
QJsonParseError error;//错误码
QJsonDocument jsonDocument = QJsonDocument::fromJson(picData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音乐歌词JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject jsonobject = jsonDocument.object();
return jsonobject["url"].toString();
}
MusicPlayer 音乐播放类
- 继承了QMediaPlayer类,用Qt的多媒体播放类来实现音乐的播放
- 在该类中我们自己要实现的时歌词的修整,因为在网络中解析出来的歌词时一长串的,并且开头带有时间;
QString MusicPlayer::parsingLyrics(QString lyric)
{
QStringList lyricList = lyric.split('\n');//以回车为界拆分
QString newLyric;//修改好的歌词
lyricTime.clear();//清空容器中的时间
int line = 0;//初始化行号
for (int i = 0 ; i < lyricList.size(); ++i)
{
QStringList lyricLineList = lyricList[i].split(']');//以】为界分割时间和歌词
if (lyricLineList.size() != 2 || lyricLineList[1].size() < 1)
{
continue;//跳过空歌词
}
QString lyricLine = lyricLineList[1].trimmed();//去掉首尾空格
newLyric = newLyric + lyricLine + "\r\n";
QString time = lyricLineList[0].remove('[');//删除时间多余的【
if (time.size() == 8)//老歌时间格式(如:蒋大为)
{
time = time + '0';//普通歌时间是9位
}
QTime ms = QTime::fromString(time,"mm:ss.zzz");//将时间转换为毫秒
lyricTime[ms.msecsSinceStartOfDay()] = line ++;//写入容器
}
return newLyric;
}
- 设置初始音量
setVolume(50);
GraphicsView 动画展示类
- 该类还包含两个类:
DiskItem *diskItem;//唱片动画
MagnetNeedle *magnetNeedle;//唱针动画
- 窗口展示
void GraphicsView::reflushMusicPic(const QImage &pic)
{
image = pic;//展示的专辑图片
QImage argb32Image = makeARGB32Image(pic);
QImage circleImage = makeCircleImage(argb32Image);
QImage diskImage = makeDiskImage(circleImage);//重叠成圆形
diskImage = diskImage.scaled(300,300);
diskItem->setImage(diskImage);//将圆形图片设置为动画的图片
update();//更新图片
}
两个动画类
1.继承QPropertyAnimation类,而QPropertyAnimation也继承了QObject;文章来源地址https://www.toymoban.com/news/detail-436972.html
DiskItem::DiskItem(QObject *parent) : QObject(parent) ,
animation(new QPropertyAnimation(this,"anagle",this))
{
animation->setDuration(5000);//周期
animation->setStartValue(0);//起始角度
animation->setEndValue(360);//结束角度
animation->setLoopCount(-1);//循环转到
}
QRectF DiskItem::boundingRect() const//修改坐标轴起始位置
{
return QRectF(image.width() / -2.0, image.height() / -2.0, image.width(), image.height());
}
void DiskItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->drawImage(boundingRect(),image);
}
void DiskItem::setImage(const QImage &musicImage)
{
image = musicImage;//设置动画图片
update();
}
void DiskItem::setAnimationStart()
{
animation->start();//音乐开始播放时开始转动
}
void DiskItem::setAnimationEnd()
{
animation->stop();//音乐暂停停止转动
}
到了这里,关于【基于Qt的在线音乐播放器】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!