基于Qt的在線音樂播放器
項目功能:
本在線音樂播放器的功能在于創(chuàng)建一個音樂播放器頁面,可以實現(xiàn)搜索功能通過HTTP協(xié)議獲取網(wǎng)絡(luò)中數(shù)據(jù)并解析出來,播放搜索到的歌曲并展示相關(guān)信息。效果如圖:
相關(guān)類及功能
- Musicinterface 視圖類;
主要功能:初始化窗口;設(shè)置按鈕功能和窗口內(nèi)容的顯示; - HttpHandle 網(wǎng)絡(luò)連接類;
主要功能:連接網(wǎng)絡(luò)、發(fā)送請求、接收數(shù)據(jù)、用JSON解析數(shù)據(jù); - MusicPlayer 音樂播放類;
主要功能:播放音樂、修正歌詞; - GraphicsView 動畫展示類;
主要功能:在窗口顯示專輯圖片,讓唱片隨音樂播放轉(zhuǎn)動,音樂停止而停止;唱針隨音樂播放撥動到唱片上,音樂停止歸位;
Musicinterface 視圖類
初始化歌曲列表窗口
void Musicinterface::initTableWidget()
{
ui->tableWidget_musicList->setStyleSheet("selection-background-color:pink; selection-color: white;"); //設(shè)置tableWidget QSS樣式表,背景為紅色,字體為白色
ui->tableWidget_musicList->hideColumn(0); //隱藏第一列
ui->tableWidget_musicList->hideColumn(1); //隱藏第2列
ui->tableWidget_musicList->setEditTriggers(QAbstractItemView::NoEditTriggers); //設(shè)置不可編輯
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);}"); //設(shè)置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的調(diào)色板
palette.setColor(QPalette::Highlight, QColor(Qt::transparent)); //將選中區(qū)域背景改為透明
palette.setColor(QPalette::HighlightedText, QColor(Qt::red)); //將選中區(qū)域的文字改為紅色
ui->textEdit_musicWord->setPalette(palette); //將調(diào)色板設(shè)置到textEdit
ui->textEdit_musicWord->setReadOnly(true); //設(shè)置為只讀
ui->textEdit_musicWord->document()->setDefaultTextOption(QTextOption(Qt::AlignHCenter)); //文字居中顯示
}
Qss
界面美化也可以用Qss實現(xiàn)
- 什么是Qss:Qt樣式表,他是Qt提供的一種用來自定義控件外觀的機制。
- 控件的構(gòu)成:
1)Margin:控件最外圍的透明區(qū)域,總為透明;
2)Border:控件最外圍的邊框;
3)Padding:控件的外邊框內(nèi)顯示區(qū)域的空白區(qū);
4)Content:控件最內(nèi)顯示區(qū); - 語法規(guī)則
示例:
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)選擇器:如果不設(shè)置選擇器,可能會對全局所有同類型的控件生效;此項目中常用ID選擇器:#myButton匹配所有ID為“myButton”的控件,ID實際上是該控件的ObjectName;
#pushButton_playNext//ID
{
border-image: url(:/Image/next1.png);
}
2)背景屬性:background 一次可以設(shè)置多個屬性,用空格隔開background:<color> <image> <position> <repeat>
;也可以分開設(shè)置border-image: url(:/Image/next1.png);background-color: rgb(170, 170, 255);
3) 邊框?qū)傩裕篵order 一次可以設(shè)置多個屬性,用空格隔開;/*邊界1像素 實線 顏色rgb 或者border:none 沒有邊界*/ border:1px solid rgb(180, 180, 180);
color邊框顏色、style邊框風格、image控件圖片、radius設(shè)置圓角;
4)字體屬性:可以直接在選擇字體對話框或者屬性欄填寫;
5)文本屬性:color:設(shè)置文本顏色;text-align:設(shè)置文本對齊方式;text-transform: 設(shè)置文本大小寫;word-spacing:設(shè)置單詞間距離;
- 偽狀態(tài)
hover: 鼠標懸停在指定控件時所使用的樣式;
pressed: 控件被鼠標按下時的樣式;
checked:控件被選中時的樣式;
unchecked:控件未被選中時的樣式;
示例:
#pushButton_playLast:pressed//被按下時的狀態(tài)
{
border-image: url(:/Image/last2.png);
}
搜索歌曲
//歌曲列表
void Musicinterface::on_lineEdit_search_returnPressed()
{
ui->tableWidget_musicList->clearContents(); //清除表內(nèi)所有數(shù)據(jù)(不包含表頭數(shù)據(jù)和設(shè)置的其他屬性)
ui->tableWidget_musicList->setRowCount(0); //設(shè)置當前行數(shù),為0
QString searchData = ui->lineEdit_search->text();//獲取輸入搜索框的內(nèi)容
httpHandle->searchMusicList(searchData);//搜索歌曲列表
}
按鈕功能設(shè)置
將按鈕右鍵轉(zhuǎn)到槽并實現(xiàn)該函數(shù);文章來源:http://www.zghlxwxcb.cn/news/detail-436972.html
- 雙擊播放歌曲設(shè)置
//雙擊歌曲播放
void Musicinterface::on_tableWidget_musicList_cellDoubleClicked(int row, int column)
{
Q_UNUSED(column)
QString musicId = ui->tableWidget_musicList->item(row,0)->text();//獲取row行0列數(shù)據(jù)
QString musicPicId = ui->tableWidget_musicList->item(row,1)->text();//row行0列
QString musicUrl = httpHandle->searchMusicUrl(musicId);//獲取歌曲播放網(wǎng)址
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();//播放動畫
}
- 播放與暫停按鈕設(shè)置:聲明一個槽函數(shù),當音樂播放狀態(tài)發(fā)生改變時,觸發(fā)槽函數(shù)改變當前圖標狀態(tài),在按鈕轉(zhuǎn)到槽函數(shù)中實現(xiàn)兩種音樂播放狀態(tài)的改變;
//音樂播放狀態(tài)改變與暫停播放按鈕狀態(tài)
connect(musicPlayer,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(slotReflushPlayButtonIcon(QMediaPlayer::State)));
//播放、停止按鈕的設(shè)計
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(); //獲取當前選中行
//獲取當前播放狀態(tài)
//播放或暫停
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);
}
}
}
- 上一曲、下一曲切換設(shè)置(包括按鍵狀態(tài)切換和歌曲切換,這里只寫歌曲切換代碼)
//上一曲
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);//調(diào)用雙擊播放函數(shù)
//選中上一行
ui->tableWidget_musicList->selectRow(row); //選中第line行
}
- 隨機播放與順序播放設(shè)置:當一首音樂播完時,觸發(fā)播放順序函數(shù),查看當前標志位狀態(tài)并播放下一首歌曲;
//鏈接音樂播放狀態(tài)與循環(huán)順序按鈕
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();
}
}
}
//隨機數(shù)生成
QTime time;
time = QTime::currentTime();
qsrand(time.msecsSinceStartOfDay());
int row = ui->tableWidget_musicList->rowCount(); //獲取當前共有多少行
int n = qrand() % row;
- 進度條設(shè)置
//歌曲時長
void Musicinterface::slotReflushEndTime(qint64 ms)//時長
{
ui->horizontalSlider_progressBar->setMaximum(ms);//進度條設(shè)置
QTime time = QTime::fromMSecsSinceStartOfDay(ms);
//顯示總時長
ui->label_endTime->setText(time.toString("mm:ss"));//將ms 轉(zhuǎn)化為分鐘:秒
}
//歌曲當前時間
void Musicinterface::slotReflushStartTime(qint64 ms)//當前值
{
ui->horizontalSlider_progressBar->setValue(ms);//進度條設(shè)置
QTime time = QTime::fromMSecsSinceStartOfDay(ms);
//顯示當前時長
ui->label_startTime->setText(time.toString("mm:ss"));//將ms 轉(zhuǎn)化為分鐘:秒
}
void Musicinterface::on_horizontalSlider_progressBar_sliderMoved(int position)
{
musicPlayer->setPosition(position);//進度條可拖動
}
- 歌詞滾動展示 : 從網(wǎng)絡(luò)中解析出來的歌詞上帶有時間;
//歌詞滾動
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); //將光標設(shè)置到指定位置
tc2.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);//光標設(shè)置成選中一整行,并且保持此狀態(tài)
ui->textEdit_musicWord->setTextCursor(tc2);//將設(shè)置好的光標屬性放到textEdit中
}
HttpHandle 網(wǎng)絡(luò)連接類
- Qt 實現(xiàn)HTTP協(xié)議:HTTP協(xié)議數(shù)據(jù)格式為:請求行、頭部行、和附屬體;請求數(shù)據(jù)的方式共有七種,常用的有Get和Post兩種;
- 常用的類有:
1)QNetworkRequest 網(wǎng)絡(luò)連接請求類
2)QNetworkAccessManager 網(wǎng)絡(luò)訪問管理器,使應用程序發(fā)送網(wǎng)絡(luò)請求并接收響應
3)QNetworkReply 網(wǎng)絡(luò)回復類 接收網(wǎng)絡(luò)數(shù)據(jù) - Get方法時默認的HTTP請求方法,是將請求信息作為URL的一部分發(fā)送給Web服務(wù)器,存在安全隱患,而且有的服務(wù)器可能對URL的數(shù)據(jù)長度有限制;
QByteArray HttpHandle::getSearch(const QString &url)
{
QNetworkRequest networkRequest(url);//網(wǎng)址
QEventLoop eventloop;//事件循環(huán)
QNetworkReply *networkReply = networkAccessManager->get(networkRequest);
connect(networkReply,SIGNAL(finished()),&eventloop,SLOT(quit()));//接收信息結(jié)束,事件循環(huán)停止
eventloop.exec(QEventLoop::ExcludeUserInputEvents);//阻止未接收完第一次信息時的第二次搜索
return networkReply->readAll();
}
- Post方法是在向Web服務(wù)器提交表單數(shù)據(jù)時,將請求部分放在附屬體中發(fā)送給服務(wù)器;
//將Url,頭信息、請求方式封裝成函數(shù)
//返回值是從網(wǎng)站接收到的數(shù)據(jù)
QByteArray HttpHandle::postSearch(const QString body)
{
QNetworkRequest networkRequest(QUrl("https://l-by.cn/yinyue/api.php"));//網(wǎng)址
networkRequest.setRawHeader(QByteArray("Content-Type"),QByteArray("application/x-www-form-urlencoded; charset=UTF-8"));//Head
QEventLoop eventloop;//事件循環(huán)
QNetworkReply *networkReply = networkAccessManager->post(networkRequest,body.toUtf8());
connect(networkReply,SIGNAL(finished()),&eventloop,SLOT(quit()));//接收信息結(jié)束,事件循環(huán)停止
eventloop.exec(QEventLoop::ExcludeUserInputEvents);//阻止未接收完第一次信息時的第二次搜索
return networkReply->readAll();
}
- JSON解析數(shù)據(jù)
1)QJsonParseError 用于json解析期間報錯
2)QJsonDocument 用于寫入或讀取json文檔數(shù)據(jù)
3)QJsonObject 封裝了一個json類型對象,可用來獲取json對象里的值
示例:
//搜索框查詢函數(shù),歌曲列表
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,頭信息、請求方式封裝成函數(shù)調(diào)用
QJsonParseError error;//錯誤碼
QJsonDocument jsonDocument = QJsonDocument::fromJson(musicData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音樂列表JSON數(shù)據(jù)失??!錯誤碼:" << error.errorString();
return ;
}
//解析
QJsonArray musicInfoArray = jsonDocument.array();//大數(shù)組
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);//發(fā)送信號和信息給
}
}
//歌曲播放網(wǎng)址
QString HttpHandle::searchMusicUrl(const QString &id)
{
//拼接字符串.arg()
QString body = QString(" types=url&id=%1&source=netease").arg(id);
QByteArray musicData = postSearch(body);//將Url,頭信息、請求方式封裝成函數(shù)調(diào)用
QJsonParseError error;//錯誤碼
QJsonDocument jsonDocument = QJsonDocument::fromJson(musicData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音樂地址JSON數(shù)據(jù)失敗!錯誤碼:" << 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,頭信息、請求方式封裝成函數(shù)調(diào)用
QJsonParseError error;//錯誤碼
QJsonDocument jsonDocument = QJsonDocument::fromJson(musicData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音樂歌詞JSON數(shù)據(jù)失敗!錯誤碼:" << 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,頭信息、請求方式封裝成函數(shù)調(diào)用
QJsonParseError error;//錯誤碼
QJsonDocument jsonDocument = QJsonDocument::fromJson(picData,&error);
if (error.error != QJsonParseError::NoError)
{
qDebug() << "解析音樂歌詞JSON數(shù)據(jù)失?。″e誤碼:" << error.errorString();
return QString();
}
QJsonObject jsonobject = jsonDocument.object();
return jsonobject["url"].toString();
}
MusicPlayer 音樂播放類
- 繼承了QMediaPlayer類,用Qt的多媒體播放類來實現(xiàn)音樂的播放
- 在該類中我們自己要實現(xiàn)的時歌詞的修整,因為在網(wǎng)絡(luò)中解析出來的歌詞時一長串的,并且開頭帶有時間;
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");//將時間轉(zhuǎn)換為毫秒
lyricTime[ms.msecsSinceStartOfDay()] = line ++;//寫入容器
}
return newLyric;
}
- 設(shè)置初始音量
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);//將圓形圖片設(shè)置為動畫的圖片
update();//更新圖片
}
兩個動畫類
1.繼承QPropertyAnimation類,而QPropertyAnimation也繼承了QObject;文章來源地址http://www.zghlxwxcb.cn/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);//結(jié)束角度
animation->setLoopCount(-1);//循環(huán)轉(zhuǎn)到
}
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;//設(shè)置動畫圖片
update();
}
void DiskItem::setAnimationStart()
{
animation->start();//音樂開始播放時開始轉(zhuǎn)動
}
void DiskItem::setAnimationEnd()
{
animation->stop();//音樂暫停停止轉(zhuǎn)動
}
到了這里,關(guān)于【基于Qt的在線音樂播放器】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!