【C++】QT | 音乐播放器初级 源文件

前置内容在上一篇【C++】QT | 音乐播放器初级

加载文件需要文件相关,而lrc文件适合用map容器匹配,用计时器来更新歌词:

#include <QMap>                                 // map容器
#include <QFile>                                // 文件相关
#include <QTimer>
public:
    void ReadLRC(const QString & filepath);			// 读取对应路径的歌词文件

public slots:
    void SetLRC();							      // 槽函数,更新歌词

private:
    std::map<long long, QString> LRCMap;			// map容器,存储歌词:<时间, 歌词>
    QTimer timer;								  // 设置定时器

在ui中增加label_LRC,并调节大小。

读取歌词文件:

ReadLRC("E:\\252QT\\202401\\Test\\music\\千百度.lrc");

......
    
long long StrToMsec(const QString & timeStr)    // 传入QString对象,传回时间(毫秒)
{
    auto leftList = timeStr.split(":");         // 先分出分钟
    if(leftList.size() != 2)                    // 没有成功分割为两段时退出
        return 0;
    auto Min = leftList[0].toInt();             // 字符第一段转为数字,即分钟

    auto rightList = leftList[1].split(".");    // 剩下的字符按.分割
    if(rightList.size() != 2)                   // 失败退出
        return 0;
    int sec = rightList[0].toInt();             // .第一段即秒
    int msec = rightList[1].toInt();            // 第二段即毫秒

    return msec + 1000 * sec + 1000 * 60 * Min; // 总毫秒
}
    
void Widget::ReadLRC(const QString & filepath)                      // 读取歌词文件
{
    LRCMap.clear();                                                 // 重置路径
    QFile file(filepath);
    if(file.open(QIODevice::ReadOnly) == true)                      // 以只读打开
    {
        QTextStream input(&file);                                   // 读入文件流
        while(input.atEnd() != true)                                // 不在末尾
        {
            QString content = input.readLine();                     // 读取一行
            QStringList LRCList = content.split("]");               // 分割时间与歌词
            if(LRCList.size() != 2)
                continue;
            QString TimeString = LRCList[0].remove("[");            // 提取时间字符串
            long long Time = StrToMsec(TimeString);                 // 获取对应毫秒数
            QString LRCString = LRCList[1];
            LRCMap[Time] = LRCString;                               // 存入容器
        }
        file.close();
    }
    else
    {
        qDebug() << "文件不存在\n";
        return;
    }
}

加载音乐文件:

p.setMedia(QUrl::fromLocalFile("E:\\252QT\\202401\\Test\\music\\千百度.mp3"));

将定时器与歌词更新绑定:

connect(&timer, &QTimer::timeout, this, &Widget::SetLRC);

......
    
void Widget::SetLRC()
{
    auto Time = p.position();                               // 获取当前的音乐进度
    for(auto ite = LRCMap.begin(); ite != LRCMap.end(); )   // 遍历LRC容器
    {
        auto PrevIte = ite++;                               // PrevIte接受ite的值,而ite向下

        // 当ite未越界,取两个时间段之间的元素
        if(ite != LRCMap.end() && PrevIte->first <= Time && ite->first > Time)
        {
            ui->label_LRC->setText(PrevIte->second);        // 设置该标签为对应歌词
        }
    }
}

在播放函数中添加定时器更新:

void Widget::PlayMusic()
{
    if(p.state() != QMediaPlayer::PlayingState)
    {
        p.play();
        timer.start(200);
        ui->pushButton_play->setIcon(QIcon(":/image/pause.png"));
    }
    else
    {
        p.pause();
        timer.stop();
        ui->pushButton_play->setIcon(QIcon(":/image/play.png"));
    }
}

此时编译运行,即可看到播放时出现歌词。

文件

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMediaPlayer>
#include <QMap>                                 // map容器
#include <QFile>                                // 文件相关
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
    void ReadLRC(const QString & filepath);

public slots:
    void DurationChanged();
    void PlayMusic();
    void PositionChanged();

    void SetLRC();

private:
    Ui::Widget *ui;
    QMediaPlayer p;
    std::map<long long, QString> LRCMap;
    QTimer timer;

};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle("Test");                               // 标题
    this->setWindowIcon(QIcon(":/image/player.png"));           // 应用图标

    ui->pushButton_play->setIcon(QIcon(":/image/play.png"));    // ui中该按钮设置图标

    ReadLRC("E:\\Test\\music\\千百度.lrc");

    p.setMedia(QUrl::fromLocalFile("E:\\Test\\music\\千百度.mp3"));

    // 歌曲加载完毕,参数修改
    connect(&p, &QMediaPlayer::durationChanged, this, &Widget::DurationChanged);

    // 将pushButton_play按钮的clicked动作与this对象的PlayMusic方法绑定
    connect(ui->pushButton_play, &QPushButton::clicked, this, &Widget::PlayMusic);

    connect(&p, &QMediaPlayer::positionChanged, this, &Widget::PositionChanged);

    connect(ui->horizontalSlider, &QSlider::sliderMoved, &p, &QMediaPlayer::setPosition);

    connect(&timer, &QTimer::timeout, this, &Widget::SetLRC);
}

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

long long StrToMsec(const QString & timeStr)    // 传入QString对象,传回时间(毫秒)
{
    auto leftList = timeStr.split(":");         // 先分出分钟
    if(leftList.size() != 2)                    // 没有成功分割为两段时退出
        return 0;
    auto Min = leftList[0].toInt();             // 字符第一段转为数字,即分钟

    auto rightList = leftList[1].split(".");    // 剩下的字符按.分割
    if(rightList.size() != 2)                   // 失败退出
        return 0;
    int sec = rightList[0].toInt();             // .第一段即秒
    int msec = rightList[1].toInt();            // 第二段即毫秒

    return msec + 1000 * sec + 1000 * 60 * Min; // 总毫秒
}

void Widget::ReadLRC(const QString & filepath)                      // 读取歌词文件
{
    LRCMap.clear();                                                 // 重置路径
    QFile file(filepath);
    if(file.open(QIODevice::ReadOnly) == true)                      // 以只读打开
    {
        QTextStream input(&file);                                   // 读入文件流
        while(input.atEnd() != true)                                // 不在末尾
        {
            QString content = input.readLine();                     // 读取一行
            QStringList LRCList = content.split("]");               // 分割时间与歌词
            if(LRCList.size() != 2)
                continue;
            QString TimeString = LRCList[0].remove("[");            // 提取时间字符串
            long long Time = StrToMsec(TimeString);                 // 获取对应毫秒数
            QString LRCString = LRCList[1];
            LRCMap[Time] = LRCString;                               // 存入容器
        }
        file.close();
    }
    else
    {
        qDebug() << "文件不存在\n";
        return;
    }
}

void Widget::DurationChanged()
{
    long long duration = p.duration();

    QString Time = QString("%1:%2").arg(duration / 1000 / 60).arg(duration / 1000 % 60);

    ui->label_MusicTime->setText(Time);

    ui->horizontalSlider->setRange(0, static_cast<int>(duration));
}

void Widget::PlayMusic()
{
    if(p.state() != QMediaPlayer::PlayingState)
    {
        p.play();
        timer.start(200);
        ui->pushButton_play->setIcon(QIcon(":/image/pause.png"));
    }
    else
    {
        p.pause();
        timer.stop();
        ui->pushButton_play->setIcon(QIcon(":/image/play.png"));
    }
}

void Widget::PositionChanged()
{
    long long position = p.position();

    QString Time = QString("%1:%2").arg(position / 1000 / 60).arg(position / 1000 % 60);

    ui->label_CurrentTime->setText(Time);

    ui->horizontalSlider->setValue(static_cast<int>(position));
}

void Widget::SetLRC()
{
    auto Time = p.position();                               // 获取当前的音乐进度
    for(auto ite = LRCMap.begin(); ite != LRCMap.end(); )   // 遍历LRC容器
    {
        auto PrevIte = ite++;                               // PrevIte接受ite的值,而ite向下

        // 当ite未越界,取两个时间段之间的元素
        if(ite != LRCMap.end() && PrevIte->first <= Time && ite->first > Time)
        {
            ui->label_LRC->setText(PrevIte->second);        // 设置该标签为对应歌词
        }
    }
}

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值