1. 程式人生 > 實用技巧 >基於Qt的網路音樂播放器,實現歌詞滾動顯示!QT還是好用的呀

基於Qt的網路音樂播放器,實現歌詞滾動顯示!QT還是好用的呀

1.思路和效果圖

先說一下大體思路:
json解析出來的lyrics歌詞(字串形式:[00:18.26]畢竟我們深愛過\r\n[00:21.74]有你陪的日子裡)中每句和每句之間有\n,所以我們利用這個換行符標識來分割字串,放在list中,這樣,我們得到的每一個字串都是時間戳+歌詞的形式,接下來,我們再繼續解析單個字串,用Qmap<int,QString>來儲存,時間作為鍵值,歌詞作為值,這樣就構成了時間對應歌詞的形式,然後通過QMediaPlayer類中positionChanged(qint64 duration)訊號呼叫槽函式onDurationChanged(qint64 duration)來顯示歌詞,positionChanged訊號會返回當前歌曲的進度,這個進度是毫秒級別的,將返回的時間與map的鍵值做對比,從而在適當的時間顯示對應的歌詞,歌詞用Label顯示。大體思路就是這樣,然後具體實現的時候,還是有許多細節需要注意的,遇到再說,還有就是上面提到的函式等等,在前面的文章中已經建立,下面的程式碼是直接寫實現,如果不知道在哪裡寫,可檢視前面幾篇文章。


2.歌詞的解析與儲存

mainwindow.h

//類成員
QMap<int,QString> lrcMap;

mianwindow.cpp

	if (valuedataObject.contains("lyrics")) //lrc
	{
		QJsonValue play_url_value = valuedataObject.take("lyrics");
		if (play_url_value.isString())
		{
			QString play_lrcStr = play_url_value.toString();
			if (play_urlStr != "")
			{
				if (play_lrcStr != "")
				{	//將整個歌詞給s
					QString s = play_lrcStr;
					// s1 用列表的形式儲存每一句歌詞
					QStringList s1 = s.split("\n");
					for (int i = 3; i < s1.size() - 1; i++)
					{
						QString ss1 = s1.at(i);
						//歌詞中開頭有一些是無意義的字元,用正則表示式判斷,只儲存包含有時間戳的字串。
						QRegExp ipRegExp = QRegExp("\\[\\d\\d\\S\\d\\d\\S\\d\\d\\]");
						//若包含則返回flase
						bool match = ipRegExp.indexIn(ss1);
						if (match == false)
						{
							//時間解析格式(分*60+秒)*100+釐秒
							int s_1 = ss1.mid(1, 2).toInt();      //分
							int s_2 = ss1.mid(4, 2).toInt();      //秒
							int s_3 = ss1.mid(7, 2).toInt();      //釐秒
							int s_count = (s_1 * 60 + s_2) * 100 + s_3;   //規定寫法
							int lrctime = s_count;
							QString lrcstr = ss1.mid(10);
							//用Qmap來儲存
							lrcMap.insert(lrctime, lrcstr);
						}
					}
				}
				else
				{
					//沒有歌詞;
				}
			}
		}
	}

由於json返回的歌詞裡面的時間表示是[02:12.85](.後面的數字表示85/100秒)這種形式,而positionChanged返回的是以毫秒的形式,為了能夠做對比,我們規定一種通用的表示方法:

時間解析格式(分*60+秒)*100+釐秒,這個釐秒就是小數點後面的數。


3.onDurationChanged()

void MainWindow::onPositionChanged(qint64 position)
{
    //時間標籤得法
    //(分*60+秒)*100+釐秒
    int pos = position/10;
    QMap<int, QString>::iterator iter = lrcMap.begin();
        while (iter != lrcMap.end())
        {
            if(pos-50<=iter.key()&& pos+50>=iter.key())
            {
                    int j=0;
                    if(iter != lrcMap.begin())
                    {
                        iter--;
                        ui->label_20->setText(iter.value());
                        j++;
                    }
                    if(iter != lrcMap.begin())
                    {
                        iter--;
                        ui->label_19->setText(iter.value());
                        j++;
                    }

                    if(iter != lrcMap.begin())
                    {
                        iter--;
                        ui->label_6->setText(iter.value());
                        j++;
                    }
                    for(;j>0;j--)
                    {
                        iter++;
                    }
               //中間
               ui->label_21->setText(iter.value());
               iter++;
               if(iter != lrcMap.end())
               {
                   ui->label_22->setText(iter.value());
               }
               else
               {
                   ui->label_22->setText("");
                   return;
               }
               iter++;
               if(iter != lrcMap.end())
               {
                   ui->label_23->setText(iter.value());
               }
               else
               {
                   ui->label_23->setText("");
                   return;
               }
               iter++;
               if(iter != lrcMap.end())
               {
                   ui->label_24->setText(iter.value());
               }
               else
               {
                   ui->label_24->setText("");
                   return;
               }
               iter++;
               if(iter != lrcMap.end())
               {
                   ui->label_25->setText(iter.value());
               }
               else
               {
                   ui->label_25->setText("");
                   return;
               }
               iter++;
               if(iter != lrcMap.end())
               {
                   ui->label_26->setText(iter.value());
               }
               else
               {
                   ui->label_26->setText("");
                   return;
               }
               iter++;
               if(iter != lrcMap.end())
               {
                   ui->label_27->setText(iter.value());
               }
               else
               {
                   ui->label_27->setText("");
                   return;
               }
            }
            iter++;
        }
}

label_21等10標籤用於顯示歌詞,label_21匹配當前時間顯示的歌詞,並且把該歌詞前面的歌詞和後面的歌詞分別傳送給其他對應的標籤。這樣就實現了動態效果。


4.總結

雖然程式碼很少,但是完成這個還是用了很長時間實現,反覆修改,反覆崩潰,沒實現前,覺得這個功能,要是能實現多好,實現了後又覺得自己寫的太簡單了,而且效果有一點僵硬,並沒有人家QQ 酷狗啊什麼,歌詞是慢慢往上滑,我這個是直接顯示,後面會研究研究怎麼滑動顯示,讓人看見更加平滑。學習就是這樣,來回不斷重複,對待問題的看法,邏輯的推理,思維的跳躍,從不會到實現,再到不滿足再實現。可執行檔案不是你的財富,修改過程中的經驗才是,我是花狗,一名苟且偷生的大專生,我們下篇見。


整個專案原始碼獲取加群哦:1136192749