Qt 音乐播放器

一、实现功能:
1、读取歌曲文件,实现歌曲的播放;
2、采用Qt Designer实现歌曲的暂停和播放,歌曲名列表和当前播放歌曲名的显示,上一曲和下一曲歌曲的更换,播放模式的设置,音量的改变,歌曲播放进度的改变;
3、读取歌词文件,实现歌词的显示;
4、利用QSetting增加歌曲文件和歌词文件的设置功能;
5、界面汉化;
6、使用CSS进行界面美化。

二、实现:
1、创建工程
1> 单击运行 Qt Creator,进入欢迎界面,单击 “New Project”,创建一个新的工程。
1-1 创建一个新工程,建立一个桌面项目
2> 单击选择项目“Application”->“Qt Widgets Application”选项,单击”choose”。
1-2 保存项目
3> 选择项目路径,并自定义自己项目的名字。注意,保存项目路径中不能有中文字。项目命名没有大小写要求。单击下一步。
4> 弹出“Kit Selection”界面,系统已经默认指定C++编译器和调试器,单击下一步。
5> 根据实际需要,选择一个“基类”。这里选择QWidget对话框类作为基类。勾选“创建界面”复选框,表示需要采用自带的界面设计器来设计界面,否则需要利用代码完成界面的设计。
6> 单击“下一步”,然后单击“完成”。

2、界面设计:
双击 musicwidget.ui ,进入界面设计器Qt Designer编辑状态,进行设计器编程。
通过拖拽空间容器栏的控件设计界面。
2-1 界面的简单设计
根据自己的需要,可以修改控件的属性。

3、为了编写程序以及查看路径的方便,可以自定义makefile的路径。
单击“项目”->“构建目录”,在工程目录下,新建output目录,将makefile的路径自定义为output。
3-1 makefile的路径修改

4、将歌曲文件和歌词文件复制在工程目录下。

5、资源层
通过读取歌曲文件,实现音乐的播放。
在 “项目”栏下,右键 工程文件名,添加新文件(歌曲文件)
选择“C++ Class”->“choose”
5-1 添加歌曲文件类
1> 文件操作

songsfile.cpp

#include "songsfile.h"

QString Songsfile::m_songsPath = tr("../song/");

Songsfile::Songsfile(QObject *parent) : QObject(parent)
{
    m_songFormat = tr(".mp3");
    m_songDir = QDir(m_songsPath);

    m_songsList = m_songDir.entryInfoList(QStringList() << "*.mp3",
                                      QDir::Files, QDir::Name);
}

void Songsfile::initSongListAndSongNameList(QMediaPlaylist &m_songsPlayList,
                                 QStringList &m_songsNameList)
{

    foreach (QFileInfo fileInfo, m_songsList)
    {
        m_songsNameList.append(fileInfo.fileName().remove(".mp3"));

        QUrl song = QUrl::fromLocalFile(fileInfo.absoluteFilePath());

        if (fileInfo.exists())
        {
            if (fileInfo.suffix().toLower() == QLatin1String("m3u"))  //后缀
            {
                m_songsPlayList.load(song);
            }else
            {
                m_songsPlayList.addMedia(song);
            }
        }else
        {
            if (song.isValid())
            {
                m_songsPlayList.addMedia(song);
            }
        }
    }

}

2> 我们使用qt提供的多媒体库,
在 .pro 文件中添加库,

QT       += core gui multimedia

3> 实现歌曲播放

musicwidget.cpp

m_songsfile->initSongListAndSongNameList(m_songsPlayList, m_songsNameList);

    m_musicPlayer.setMedia(&m_songsPlayList);
    m_musicPlayer->getSongsPlayList().setCurrentIndex(0); 
    m_musicPlayer.play();

此时即可实现简单的歌曲播放功能

6、逻辑层
新建一个 musicplayer.cpp 的实现逻辑功能的文件

#include "musicplayer.h"

MusicPlayer::MusicPlayer(QObject *parent) : QObject(parent)
{
    m_songsfile = new Songsfile(this);
    m_lyricFile = new LyricFile(this);

    m_songsfile->initSongListAndSongNameList(m_songsPlayList, m_songsNameList);

    m_musicPlayer.setMedia(&m_songsPlayList);
    m_musicPlayer.setVolume(INIT_SYSTEM_VOLUME);

    connect(&m_musicPlayer, SIGNAL(durationChanged(qint64)),
            this, SLOT(slotDurationChanged(qint64)));
    connect(&m_musicPlayer, SIGNAL(positionChanged(qint64)),
            this, SLOT(slotPositionChanged(qint64)));
}

MusicPlayer::~MusicPlayer(void)
{

}

void MusicPlayer::slotDurationChanged(qint64 durationTime)
{
    m_durationTime = durationTime / TIME_MS_DURATION;

    QTime totalTime((m_durationTime / 3600) % 24, (m_durationTime / 60) % 60,
                       m_durationTime % 60, (m_durationTime * 1000) % 1000);

    QString totalTimeChanged = totalTime.toString("mm:ss");

    emit signalDurationChanged(totalTimeChanged);   //发送信号  歌曲长度改变
}

void MusicPlayer::slotPositionChanged(qint64 positionTime)
{
    m_positionTime = positionTime / TIME_MS_DURATION;

    QTime currentTime((m_positionTime / 3600) % 24, (m_positionTime / 60) % 60,
                      m_positionTime % 60, (m_positionTime * 1000) % 1000);

    QString currenTimeChanged = currentTime.toString("mm:ss");

    emit signalPositionChanged(currenTimeChanged);    //发送信号  歌曲当前进度改变
}



QMediaPlayer &MusicPlayer::getCurrentPlayer(void)  //当前播放器
{
    return m_musicPlayer;
}

QMediaPlaylist &MusicPlayer::getSongsPlayList(void)  //获取歌曲列表
{
    return m_songsPlayList;
}

QStringList &MusicPlayer::getSongsNameList(void)   //获取歌名列表
{
    return m_songsNameList;
}

qint64 &MusicPlayer::getDurationTime(void)    //获取歌曲总长度
{
    return m_durationTime;
}

qint64 &MusicPlayer::getPositionTime(void)   //获取歌曲当前进度
{
    return m_positionTime;
}

void MusicPlayer::setPositionTime(int position)  //设置歌曲当前进度
{
    m_positionTime = position;
}

void MusicPlayer::getCurrentSongLyric(void) //歌词文件
{
    m_lyricFile = new LyricFile();

    m_lyricList.clear();
    m_lyricShow.clear();
    m_lyricFile->getCurrentSongLyric(m_lyricList, m_lyricShow);
}

QStringList &MusicPlayer::getCurrentLyricList(void) //歌词列表
{
    return m_lyricList;
}

QMap<qint64, qint64> &MusicPlayer::getCurrentLyricMapIndex(void) //歌词索引
{
    return m_lyricShow;
}
  • 此逻辑已经加入了歌词的逻辑实现。

7、界面层

musicwidget.cpp

#include "musicwidget.h"
#include "musicplayer.h"
#include "ui_musicwidget.h"

#include <QDebug>

#define TIME_MS_DURATION 1000
#define INIT_SYSTEM_VOLUME 50

QString MusicWidget::m_currentSongName = "\0";

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

    m_musicPlayer = new MusicPlayer(this);

    m_currentLyricFont = QFont("current_font", 13, QFont::DemiBold);  //当前行字体
    m_otherLyricFont = QFont();    //其他行字体

    ui->lw_songNameList->addItems(m_musicPlayer->getSongsNameList());  //添加歌曲列表

    ui->volume_Slider->setValue(INIT_SYSTEM_VOLUME);  //初始化音量

    m_musicPlayer->getSongsPlayList().setCurrentIndex(0);    //初始化播放歌曲,设置当前歌曲名,设置歌曲列表的当前歌曲
    changeCurrentSongNameAndIndex();

    m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::Loop); //初始化为循环播放
    ui->cb_playMode->setCurrentIndex(3);

    connect(m_musicPlayer, SIGNAL(signalDurationChanged(QString)),
            this, SLOT(slotDurationChanged(QString)));
    connect(m_musicPlayer, SIGNAL(signalPositionChanged(QString)),
            this, SLOT(slotCurrentChanged(QString)));
}

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

/******************字体的居中和一般颜色********************/
void MusicWidget::changeLyricForm(void)
{
    for (int i = 0; i < m_musicPlayer->getCurrentLyricList().size(); i++)
    {
        ui->lw_lyricList->item(i)->setTextAlignment(Qt::AlignCenter);  //居中
        ui->lw_lyricList->item(i)->setForeground(Qt::blue);  //字体颜色
    }

}

/**************更换歌曲时歌词的改变*****************/
void MusicWidget::changeLyric(void)
{
    m_currentSongName = ui->lb_SongsName->text();

    m_musicPlayer->getCurrentSongLyric();
    ui->lw_lyricList->clear();
    ui->lw_lyricList->addItems(m_musicPlayer->getCurrentLyricList());

    changeLyricForm();
}

/*****************当前行的字体改变*******************/
void MusicWidget::changeLyricCurrentRow(void)
{
    if (m_musicPlayer->getCurrentLyricMapIndex().contains(
                                                m_musicPlayer->getPositionTime()))
    {
        m_currentRow = m_musicPlayer->getCurrentLyricMapIndex().value(
                                        m_musicPlayer->getPositionTime());  //当前行索引
        m_maxRows = m_musicPlayer->getCurrentLyricMapIndex().value(
                    m_musicPlayer->getCurrentLyricMapIndex().keys().last()); //歌词最大行索引

        ui->lw_lyricList->setCurrentRow(m_currentRow);

        ui->lw_lyricList->item(m_currentRow)->setForeground(Qt::green);
        ui->lw_lyricList->item(m_currentRow)->setFont(m_currentLyricFont);  //设置当前行的字体

        if (m_currentRow > 0)   //恢复其他行的字体
        {
            for (int i = 0; i < m_currentRow; i++)
            {
                ui->lw_lyricList->item(i)->setForeground(Qt::blue);
                ui->lw_lyricList->item(i)->setFont(m_otherLyricFont);
            }

            for (int i = m_currentRow+1; i <= m_maxRows; i++)
            {
                 ui->lw_lyricList->item(i)->setForeground(Qt::blue);
                 ui->lw_lyricList->item(i)->setFont(m_otherLyricFont);
            }
        }
    }
}

/****************当前歌曲名和索引的改变*******************/
void MusicWidget::changeCurrentSongNameAndIndex(void)
{
    ui->lb_SongsName->setText(m_musicPlayer->getSongsNameList().at(
                                  m_musicPlayer->getSongsPlayList().currentIndex()));
    ui->lw_songNameList->setCurrentRow(m_musicPlayer->getSongsPlayList().currentIndex());
}

/*******************歌曲总长度的改变**************************/
void MusicWidget::slotDurationChanged(QString totalTime)
{
    ui->lb_Time->setText(totalTime);
    ui->Total_Slider->setMaximum(m_musicPlayer->getDurationTime());

    changeCurrentSongNameAndIndex();
    changeLyric();
}

/*******************歌曲当前进度的改变***********************/
void MusicWidget::slotCurrentChanged(QString positionTime)
{
    ui->lb_CurrentTime->setText(positionTime);
    ui->Total_Slider->setValue(m_musicPlayer->getPositionTime());

    changeLyricCurrentRow();
}

/**************播放和暂停*****************/
void MusicWidget::on_pb_play_clicked()
{
    if (ui->pb_play->text() == tr("play"))
    {
        ui->pb_play->setText(tr("pause"));
        m_musicPlayer->getCurrentPlayer().play();
    }else if (ui->pb_play->text() == tr("pause"))
    {
        ui->pb_play->setText(tr("play"));
        m_musicPlayer->getCurrentPlayer().pause();
    }
}

/********************音量调节***********************/
void MusicWidget::on_volume_Slider_sliderMoved(int position)
{
    m_musicPlayer->getCurrentPlayer().setVolume(position);
    ui->volume_Slider->setValue(position);
}

/**************************歌曲进度调节*************************/
void MusicWidget::on_Total_Slider_sliderMoved(int position)
{
    m_musicPlayer->getCurrentPlayer().setPosition(position * TIME_MS_DURATION);
}

/***************************双击歌曲名***************************/
void MusicWidget::on_lw_songNameList_doubleClicked(const QModelIndex &index)
{
    m_musicPlayer->getSongsPlayList().setCurrentIndex(index.row());
    m_musicPlayer->getCurrentPlayer().play();
    ui->pb_play->setText(tr("pause"));

    changeCurrentSongNameAndIndex();

}

/******************上一曲**********************/
void MusicWidget::on_pb_pre_clicked()
{

    if (m_musicPlayer->getSongsPlayList().currentIndex() <= 0)
    {
        m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::Loop);  //播放列表循环模式
    }

    m_musicPlayer->getSongsPlayList().setCurrentIndex(m_musicPlayer->
                                                      getSongsPlayList().previousIndex());
    m_musicPlayer->getCurrentPlayer().play();

    changeCurrentSongNameAndIndex();
}

/********************下一曲*********************/
void MusicWidget::on_pb_next_clicked()
{
    m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::Loop);

    m_musicPlayer->getSongsPlayList().setCurrentIndex(m_musicPlayer->
                                                      getSongsPlayList().nextIndex());
    m_musicPlayer->getCurrentPlayer().play();

    changeCurrentSongNameAndIndex();
}

/***************************播放模式*****************************/
void MusicWidget::on_cb_playMode_currentIndexChanged(int index)
{
    switch (index) {
    case ONCE:
        m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
        break;
    case ONELOOP:
        m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
        break;
    case SEQUENTIAL:
        m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::Sequential);
        break;
    case LOOP:
        m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::Loop);
        break;
    case RANDOM:
        m_musicPlayer->getSongsPlayList().setPlaybackMode(QMediaPlaylist::Random);
        break;
    default:
        break;
    }
}

void MusicWidget::on_pB_setting_clicked()
{
    m_setting = new Setting();
    m_setting->show();
}

8、加入歌词文件以及逻辑和界面设计(逻辑和界面已在前面的代码中实现)

#include "lyricfile.h"
#include <QFile>
#include "musicwidget.h"
#include <QTextStream>
#include <QDebug>

QString LyricFile::m_lyricPath = tr("../lyric/");

LyricFile::LyricFile(QObject *parent) : QObject(parent)
{
    m_LyricDir = m_lyricPath;
    m_LyricFormat = tr(".lrc");
}

void LyricFile::getCurrentSongLyric(QStringList &LyricList,
                         QMap<qint64, qint64> &LyricShow)
{
    QString lyricLine;

    QString pos_Lyric;
    QString lyric;

    qint64 lyricTime;
    qint64 index = 0;

    QStringList lyricLinediv;
    QStringList lyricTimediv;

    QFile lyricsFile(m_LyricDir + MusicWidget::m_currentSongName + m_LyricFormat);

    if (lyricsFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "file of Lyric...";
        QTextStream lineStream(&lyricsFile);

        while (!lineStream.atEnd())
        {
            lyricLine = lineStream.readLine();
            lyricLinediv = lyricLine.split("]");  //分割每一行

            pos_Lyric = lyricLinediv.at(0).mid(1, 5);  //分割的前半部分取来时间
            lyric = lyricLinediv.at(1);           //后半部分是歌词

            LyricList.append(lyric);

            lyricTimediv = pos_Lyric.split(":");
            lyricTime = (lyricTimediv.at(0).toInt() * 60) + (lyricTimediv.at(1).toInt());

            LyricShow.insert(lyricTime, index++);

            qDebug() << lyricTime << "    " << index;

            lyric.clear();
        }
    }

}

9、实现设置功能
在工程下新建一个“Qt设计师界面类”,

这里需要新建一个 .ini 文件,用于存放初始的歌曲文件路径和歌词文件路径

9-1 user.ini

setting.cpp

#include "setting.h"
#include "ui_setting.h"

#include <QFileDialog>

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

    Songsfile::m_songsPath.clear();
    LyricFile::m_lyricPath.clear();

    initSettingWidget();
}

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

void Setting::initSettingWidget(void)
{
    readPath(tr("../user.ini"), "SONG_PATH", Songsfile::m_songsPath);
    readPath(tr("../user.ini"), "LYRIC_PATH", LyricFile::m_lyricPath);

    ui->lE_songPath->setText(Songsfile::m_songsPath);
    ui->lE_lyricPath->setText(LyricFile::m_lyricPath);
}

bool Setting::readPath(QString path, QString key, QString &value)
{
    value = QString("");
    if (path.isEmpty() || key.isEmpty())
    {
        return false;
    }else
    {
        QSettings config(path, QSettings::IniFormat);

        value = config.value(QString("config/")+key).toString();

        return true;
    }
}

bool Setting::writePath(QString path, QString key, QString value)
{
    if (path.isEmpty() || key.isEmpty())
    {
        return false;
    }else
    {
        QSettings config(path, QSettings::IniFormat);

        config.beginGroup("config");
        config.setValue(key, value);
        config.endGroup();

        return true;
    }
}

void Setting::on_pB_songPath_clicked()
{
    Songsfile::m_songsPath = QFileDialog::getExistingDirectory();
    ui->lb_SongPath->setText(Songsfile::m_songsPath);
}

void Setting::on_pB_lyricPath_clicked()
{
    LyricFile::m_lyricPath = QFileDialog::getExistingDirectory();
    ui->lE_lyricPath->setText(LyricFile::m_lyricPath);
}

void Setting::on_pB_save_clicked()
{
    writePath("../user.ini", "SONG_PATH", ui->lb_SongPath->text());
    writePath("../user.ini", "LYRIC_PATH", ui->lE_lyricPath->text());

    this->hide();
}

void Setting::on_pB_cancle_clicked()
{
    this->hide();
}

10、效果图
这里写图片描述

  • 28
    点赞
  • 206
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Qt中实现音乐播放器歌词可以通过以下步骤实现: 1. 创建一个QLabel用于显示当前播放的歌词,设置其字体、颜色、对齐方式等属性。 2. 创建一个QListWidget用于显示所有的歌词,将其隐藏。 3. 读取歌词文件,将歌词按照时间轴进行排序,存储到一个QMap中,其中key为歌词出现的时间,value为歌词内容。 4. 在音乐播放器中添加一个QTimer,每隔一段时间获取当前播放时间,从QMap中查找对应的歌词,将其显示在QLabel中。 5. 根据当前播放时间,将QListWidget中对应的歌词项高亮显示,同时将其前面和后面的歌词发送给其他对应的QLabel,实现动态效果。 以下是一个简单的示例代码: ```python from PyQt5.QtCore import Qt, QTimer from PyQt5.QtGui import QFont, QColor from PyQt5.QtWidgets import QWidget, QLabel, QListWidget, QListWidgetItem, QHBoxLayout, QVBoxLayout class MusicPlayer(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): # 创建QLabel用于显示当前播放的歌词 self.lyric_label = QLabel(self) self.lyric_label.setAlignment(Qt.AlignCenter) self.lyric_label.setFont(QFont('Arial', 20)) self.lyric_label.setStyleSheet('color: white') # 创建QListWidget用于显示所有的歌词 self.lyric_list = QListWidget(self) self.lyric_list.hide() # 将QLabel和QListWidget添加到水平布局中 hbox = QHBoxLayout() hbox.addWidget(self.lyric_label) hbox.addWidget(self.lyric_list) # 创建垂直布局并将水平布局添加到其中 vbox = QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox) vbox.addStretch(1) self.setLayout(vbox) # 读取歌词文件并将歌词按照时间轴进行排序 self.lyric_map = {} with open('lyric.txt', 'r', encoding='utf-8') as f: for line in f.readlines(): if line.strip() == '': continue time_str, lyric = line.strip().split(']') time = self.time2ms(time_str[1:]) self.lyric_map[time] = lyric # 创建QTimer用于更新歌词 self.timer = QTimer(self) self.timer.timeout.connect(self.updateLyric) def time2ms(self, time_str): # 将时间字符串转换为毫秒数 minute, second = time_str.split(':') return int(minute) * 60 * 1000 + int(second) * 1000 def updateLyric(self): # 获取当前播放时间 current_time = self.player.getCurrentTime() # 在QMap中查找对应的歌词 lyric = '' for time in self.lyric_map.keys(): if current_time >= time: lyric = self.lyric_map[time] else: break # 将歌词显示在QLabel中 self.lyric_label.setText(lyric) # 将QListWidget中对应的歌词项高亮显示 for i in range(self.lyric_list.count()): item = self.lyric_list.item(i) if item.data(Qt.UserRole) <= current_time: item.setForeground(QColor(255, 255, 255)) item.setBackground(QColor(0, 0, 0)) else: item.setForeground(QColor(128, 128, 128)) item.setBackground(QColor(255, 255, 255)) # 将当前歌词的前面和后面的歌词发送给其他对应的QLabel for i in range(self.lyric_list.count()): item = self.lyric_list.item(i) if item.data(Qt.UserRole) == current_time: self.lyric_label.setText(item.text()) if i > 0: self.lyric_list.item(i - 1).setForeground(QColor(255, 255, 255)) self.lyric_list.item(i - 1).setBackground(QColor(0, 0, 0)) if i < self.lyric_list.count() - 1: self.lyric_list.item(i + 1).setForeground(QColor(255, 255, 255)) self.lyric_list.item(i + 1).setBackground(QColor(0, 0, 0)) def loadLyric(self, lyric_file): # 读取歌词文件并将歌词按照时间轴进行排序 self.lyric_map = {} with open(lyric_file, 'r', encoding='utf-8') as f: for line in f.readlines(): if line.strip() == '': continue time_str, lyric = line.strip().split(']') time = self.time2ms(time_str[1:]) self.lyric_map[time] = lyric # 将歌词添加到QListWidget中 self.lyric_list.clear() for time, lyric in self.lyric_map.items(): item = QListWidgetItem(lyric) item.setData(Qt.UserRole, time) item.setForeground(QColor(128, 128, 128)) item.setBackground(QColor(255, 255, 255)) self.lyric_list.addItem(item) def play(self): # 开始播放音乐并启动QTimer self.player.play() self.timer.start(100) def pause(self): # 暂停播放音乐并停止QTimer self.player.pause() self.timer.stop() # 相关问题: --相关问题--:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值