用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)

一、前言

在用Qt写一个简单的音乐播放器(一):使用QMediaPlayer播放音乐中,我们已经知道如何去使用QMediaPlayer播放音乐。
在用Qt写一个简单的音乐播放器(二):增加界面(开始和暂停音乐)中,我们增加了播放音乐/暂停音乐的按钮。
在用Qt写一个简单的音乐播放器(三):增加界面(播放跳转与音量控制)中,我们加入了播放控制和音量控制。
在用Qt写一个简单的音乐播放器(四):歌曲浏览、上一曲、下一曲中,我们增加了歌曲选择的功能。
在用Qt写一个简单的音乐播放器(五):歌曲播放时间显示中,我们为歌曲播放增加播放时间显示。
那么第六篇文章来谈一谈如何显示歌词:

二、读取歌词文件

在这里插入图片描述
如图所示,首先将同名的歌词文件放入歌曲相同的路径中。
用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)_第1张图片

如上图所示,歌词文件的内容形式为一行一句,所以我们可以将歌词文件逐行读入,代码如下。
mainwindow.cpp中做如下修改

void MainWindow::on_lwMusicList_itemDoubleClicked(QListWidgetItem *item)
{
    m_PlayRow = ui->lwMusicList->row(item);
    m_mediaPlayer.stop();
    m_mediaPlayer.setMedia(QUrl::fromLocalFile(m_playPath+"/"+item->text()));
    m_mediaPlayer.play();
    QString name = item->text().left(item->text().lastIndexOf("."));
    if(!lyrics.readLyricsFile(m_playPath+"/"+name+".lrc")){
        ui->lblLyrics1->setText("未检测到歌词文件");
        ui->lblLyrics2->setText("请检查歌词文件是否存在");
    }
    lyricsID = 0;
    ui->hSliderPlayProgress->setValue(m_mediaPlayer.position());
    ui->btnPlay->setText("Pause");
    connect(timer, SIGNAL(timeout()), this, SLOT(setSliderValue()));
    connect(&m_mediaPlayer,SIGNAL(durationChanged(qint64)),this,SLOT(getduration()));
    connect(&m_mediaPlayer,SIGNAL(positionChanged(qint64)),this,SLOT(setPlayTime()));
}

新建一个lyrics类文件,加入以下代码:

bool Lyrics::readLyricsFile(QString lyricsPath)
{
    QFile file(lyricsPath);
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    QString line="";
    while((line=file.readLine())>0){
        qDebug()<<line;
        analysisLyricsFile(line);//解析歌词文件内容
    }
    return true;
}

三、解析歌词(正则表达式的使用)

歌词读取一行,我们就对这个歌词进行解析。我这里将歌词分为了两部分:时间和内容。用正则表达式匹配后,将时间计算为毫秒存入listLyricsTime,将内容存入listLyricsText。

bool Lyrics::analysisLyricsFile(QString line)
{
    if(line == NULL || line.isEmpty()){
        qDebug()<<"thie line is empty!";
        return false;
    }
    QRegularExpression regularExpression("\\[(\\d+)?:(\\d+)?(\\.\\d+)?\\](.*)?");
    int index = 0;
    QRegularExpressionMatch match;
    match = regularExpression.match(line, index);
    if(match.hasMatch()) {
        int totalTime;
        totalTime = match.captured(1).toInt() * 60000 + match.captured(2).toInt() * 1000;                    /*  计算该时间点毫秒数            */
        QString currentText =QString::fromStdString(match.captured(4).toStdString());      /*   获取歌词文本*/
        listLyricsText.push_back(currentText);
        listLyricsTime.push_back(totalTime);
        return true;
    }
    return false;
}

四、歌词显示

1.控件

用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)_第2张图片
如图所示:拖两个label,一个用来显示播放当前歌词(设置为左对齐),一个用来显示下一句歌词(设置为右对齐)。

2.代码

在播放时间改变的时候,判断当前音乐的播放时间,是否大于歌词时间,若大于,则显示歌词。代码如下:

void MainWindow::setPlayTime()
{
    if(!lyrics.getListLyricsTime().empty()&&m_mediaPlayer.position()>=lyrics.getListLyricsTime().at(lyricsID)){
        ui->lblLyrics1->setText(lyrics.getListLyricsText().at(lyricsID));
        ui->lblLyrics2->setText(lyrics.getListLyricsText().at(lyricsID+1));
        lyricsID++;
    }
    ui->lblPlayTime->setText(settime(m_mediaPlayer.position()));
}

五、效果

用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)_第3张图片
用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)_第4张图片

用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)_第5张图片
用Qt写一个简单的音乐播放器(六):显示歌词(正则表达式)_第6张图片

六、完整代码

当然这个完整也只是相对完整,不过这个基本已经很全了。

1.歌词类

Lyrics.cpp

#include "lyrics.h"

QList<QString> Lyrics::getListLyricsText() const
{
    return listLyricsText;
}

QList<int> Lyrics::getListLyricsTime() const
{
    return listLyricsTime;
}

Lyrics::Lyrics(QString lyricsPath)
{
    this->lyricsPath = lyricsPath;
}
Lyrics::Lyrics()
{
}

bool Lyrics::readLyricsFile(QString lyricsPath)
{
    QFile file(lyricsPath);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        listLyricsText.clear();
        listLyricsTime.clear();
        return false;
    }
    QString line="";
    while((line=file.readLine())>0){
        qDebug()<<line;
        analysisLyricsFile(line);
    }
    return true;
}

bool Lyrics::analysisLyricsFile(QString line)
{
    if(line == NULL || line.isEmpty()){
        qDebug()<<"thie line is empty!";
        return false;
    }
    QRegularExpression regularExpression("\\[(\\d+)?:(\\d+)?(\\.\\d+)?\\](.*)?");
    int index = 0;
    QRegularExpressionMatch match;
    match = regularExpression.match(line, index);
    if(match.hasMatch()) {
        int totalTime;
        totalTime = match.captured(1).toInt() * 60000 + match.captured(2).toInt() * 1000;                    /*  计算该时间点毫秒数            */
        QString currentText =QString::fromStdString(match.captured(4).toStdString());      /*   获取歌词文本*/
        qDebug()<<totalTime;
        qDebug()<<currentText;
        listLyricsText.push_back(currentText);
        listLyricsTime.push_back(totalTime);
        return true;
    }
    return false;
}


lyrics.h

#ifndef LYRICS_H
#define LYRICS_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
class Lyrics
{
private:
    QString lyricsPath;
    QList<QString> listLyricsText;
    QList<int> listLyricsTime;
public:
    Lyrics(QString lyricsPath);
    Lyrics();
    bool readLyricsFile(QString lyricsPath);
    bool analysisLyricsFile(QString line);
    QList<QString> getListLyricsText() const;
    QList<int> getListLyricsTime() const;
};

#endif // LYRICS_H

2.mainwindow

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    timer = new QTimer();
    timer->setInterval(2000);
    timer->start();
    ui->vSliderVolume->setVisible(false);
    QString fileName = "D:/music";
    QDir dir(fileName);
    QStringList nameFilters;
    nameFilters << "*.mp3";
    QStringList files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name);
    ui->lwMusicList->addItems(files);
    m_playPath = fileName;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btnPlay_clicked()
{
    if(QMediaPlayer:: PlayingState == m_mediaPlayer.state()){
        m_mediaPlayer.pause();
        ui->btnPlay->setText("Play");
    }
    else{
        m_mediaPlayer.play();
        ui->btnPlay->setText("Pause");
    }
}


void MainWindow::on_hSliderPlayProgress_sliderMoved(int position)
{
    m_mediaPlayer.setPosition(m_mediaPlayer.duration()*position/100);
}
void MainWindow::setSliderValue()
{
    ui->hSliderPlayProgress->setValue(m_mediaPlayer.position()*100/m_mediaPlayer.duration());
    if(m_mediaPlayer.position()>=m_mediaPlayer.duration()){
        on_btnNextMusic_clicked();
    }
}

void MainWindow::on_vSliderVolume_sliderMoved(int position)
{
    m_mediaPlayer.setVolume(position);
}

void MainWindow::on_lwMusicList_itemDoubleClicked(QListWidgetItem *item)
{
    m_PlayRow = ui->lwMusicList->row(item);
    m_mediaPlayer.stop();
    m_mediaPlayer.setMedia(QUrl::fromLocalFile(m_playPath+"/"+item->text()));
    m_mediaPlayer.play();
    QString name = item->text().left(item->text().lastIndexOf("."));
    if(!lyrics.readLyricsFile(m_playPath+"/"+name+".lrc")){
        ui->lblLyrics1->setText("未检测到歌词文件");
        ui->lblLyrics2->setText("请检查歌词文件是否存在");
    }
    lyricsID = 0;
    ui->hSliderPlayProgress->setValue(m_mediaPlayer.position());
    ui->btnPlay->setText("Pause");
    connect(timer, SIGNAL(timeout()), this, SLOT(setSliderValue()));
    connect(&m_mediaPlayer,SIGNAL(durationChanged(qint64)),this,SLOT(getduration()));
    connect(&m_mediaPlayer,SIGNAL(positionChanged(qint64)),this,SLOT(setPlayTime()));
}

void MainWindow::on_btnAddMusic_clicked()
{
    QString fileName = QFileDialog::getExistingDirectory(NULL,"Select Music Dir",".",NULL);
    QDir dir(fileName);
    QStringList nameFilters;
    nameFilters << "*.mp3";
    QStringList files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name);
    ui->lwMusicList->addItems(files);
    m_playPath = fileName;
}

void MainWindow::on_btnPreMusic_clicked()
{
    if(m_PlayRow == 0){
        m_PlayRow = ui->lwMusicList->count() - 1;
    }
    else{
        m_PlayRow--;
    }
    QListWidgetItem *item = ui->lwMusicList->item(m_PlayRow);
    item->setSelected(true);
    m_mediaPlayer.stop();
    m_mediaPlayer.setMedia(QUrl::fromLocalFile(m_playPath+"/"+item->text()));
    m_mediaPlayer.play();
}

void MainWindow::on_btnNextMusic_clicked()
{
    if(m_PlayRow + 1 == ui->lwMusicList->count()){
        m_PlayRow = 0;
    }
    else{
        m_PlayRow++;
    }
    QListWidgetItem *item = ui->lwMusicList->item(m_PlayRow);
    item->setSelected(true);
    m_mediaPlayer.stop();
    m_mediaPlayer.setMedia(QUrl::fromLocalFile(m_playPath+"/"+item->text()));
    m_mediaPlayer.play();
}

void MainWindow::on_btnVolume_clicked()
{
    if(ui->vSliderVolume->isVisible()){
        ui->vSliderVolume->setVisible(false);
    }else{
        ui->vSliderVolume->setVisible(true);
    }
}

void MainWindow::on_vSliderVolume_sliderReleased()
{
     ui->vSliderVolume->setVisible(false);
}
QString MainWindow::settime(int time)
{
    int h,m,s;
    time /= 1000;  //获得的时间是以毫秒为单位的
    h = time/3600;
    m = (time-h*3600)/60;
    s = time-h*3600-m*60;
    return QString("%1:%2:%3").arg(h).arg(m).arg(s);
}

void MainWindow::getduration()
{
    playtime = m_mediaPlayer.duration();
    ui->lblMusicTime->setText(settime(playtime));
}
void MainWindow::setPlayTime()
{
    if(!lyrics.getListLyricsTime().empty()&&m_mediaPlayer.position()>=lyrics.getListLyricsTime().at(lyricsID)&&lyricsID<lyrics.getListLyricsTime().size()-1){
        ui->lblLyrics1->setText(lyrics.getListLyricsText().at(lyricsID));
        ui->lblLyrics2->setText(lyrics.getListLyricsText().at(lyricsID+1));
        lyricsID++;
    }
    ui->lblPlayTime->setText(settime(m_mediaPlayer.position()));
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include  // 包含头文件
#include 
#include 
#include 
#include 
#include 
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    QString settime(int time);

private slots:
    void on_btnPlay_clicked();

    void on_hSliderPlayProgress_sliderMoved(int position);

    void setSliderValue();

    void on_vSliderVolume_sliderMoved(int position);

    void on_lwMusicList_itemDoubleClicked(QListWidgetItem *item);

    void on_btnAddMusic_clicked();

    void on_btnPreMusic_clicked();

    void on_btnNextMusic_clicked();

    void on_btnVolume_clicked();

    void on_vSliderVolume_sliderReleased();

    void getduration();

    void setPlayTime();

private:
    Ui::MainWindow *ui;
    QMediaPlayer m_mediaPlayer; // 实例化对象
    QTimer *timer; //定时器
    QString m_playPath;
    Lyrics lyrics;
    int m_PlayRow;
    int playtime;
    int lyricsID = 0;
};

#endif // MAINWINDOW_H

七、最后

从无到有,从最开始的播放音乐、开始、暂停、播放时间、跳转播放、音量控制、选择歌曲,到今天的歌词显示,一个简单的本地音乐播放器也终于写完了。当然它很丑,但是至少也是基本的功能也都有不是,剩下的界面美化啊,网络播放啊,等等功能吧,以后慢慢优化吧,当然现在这个代码也是有一定问题的,bug不少,代码结构也不好,以后功能越来越多的时候,肯定是要重构的。
用Qt写一个简单的音乐播放器(七):界面美化(QSS样式表)

你可能感兴趣的:(C++,Qt)