大家好,又见面了,我是你们的朋友全栈君。
一、实现功能: 1、读取歌曲文件,实现歌曲的播放; 2、采用Qt Designer实现歌曲的暂停和播放,歌曲名列表和当前播放歌曲名的显示,上一曲和下一曲歌曲的更换,播放模式的设置,音量的改变,歌曲播放进度的改变; 3、读取歌词文件,实现歌词的显示; 4、利用QSetting增加歌曲文件和歌词文件的设置功能; 5、界面汉化; 6、使用CSS进行界面美化。
二、实现: 1、创建工程 1> 单击运行 Qt Creator,进入欢迎界面,单击 “New Project”,创建一个新的工程。
2> 单击选择项目“Application”->“Qt Widgets Application”选项,单击”choose”。
3> 选择项目路径,并自定义自己项目的名字。注意,保存项目路径中不能有中文字。项目命名没有大小写要求。单击下一步。 4> 弹出“Kit Selection”界面,系统已经默认指定C++编译器和调试器,单击下一步。 5> 根据实际需要,选择一个“基类”。这里选择QWidget对话框类作为基类。勾选“创建界面”复选框,表示需要采用自带的界面设计器来设计界面,否则需要利用代码完成界面的设计。 6> 单击“下一步”,然后单击“完成”。
2、界面设计: 双击 musicwidget.ui ,进入界面设计器Qt Designer编辑状态,进行设计器编程。 通过拖拽空间容器栏的控件设计界面。
根据自己的需要,可以修改控件的属性。
3、为了编写程序以及查看路径的方便,可以自定义makefile的路径。 单击“项目”->“构建目录”,在工程目录下,新建output目录,将makefile的路径自定义为output。
4、将歌曲文件和歌词文件复制在工程目录下。
5、资源层 通过读取歌曲文件,实现音乐的播放。 在 “项目”栏下,右键 工程文件名,添加新文件(歌曲文件) 选择“C++ Class”->“choose”
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 文件,用于存放初始的歌曲文件路径和歌词文件路径
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、效果图
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/132296.html原文链接:https://javaforall.cn