大一下学期c++课程设计,做了个仿酷狗的音乐播放器。
整体做的比较粗略,现在大三看还远远不足。
软件环境:
Win8+QT5.21+Qt creator 3.01
需求分析:
:表 1 播放器控件的主要组成部分
组成控件 | 功能 |
播放/暂停按钮 | 播放当前音乐文件或者暂停播放 |
上一首按钮 | 播放列表中当前MP3文件的上一首MP3文件 |
下一首按纽 | 播放列表中当前MP3文件的下一首MP3文件 |
打开按钮 | 选择一首MP3文件 |
列表按钮 | 显示隐藏播放列表窗口 |
歌词按钮 | 显示隐藏歌词显示窗口 |
静音按钮 | 打开/关闭播放器的输出声音 |
音量控制条 | 对播放器的音量大小进行调节 |
进度控制条 | 对当前播放的MP3文件的播放进度进行调节 |
歌名显示 | 对当前播放的MP3歌名显示 |
歌曲时间显示 | 对当前播放的MP3文件的播放时间与总时长显示 |
播放模式 | 对歌曲的播放模式进行选择 |
最小化,关闭 | 把窗口最小化,关闭窗口 |
界面设计:
不足:
1) 歌词功能未能实现
2) 定位功能未能实现
3) 进度与音量必须拖动slider,否则无响应
4) 歌名过长时,歌曲播放列比例不一致
5) 当鼠标经过功能按钮时,图标无变化
6) 关闭窗口出现中文无法支持错误,无法解决,改用英文。
代码:
main.cpp
#include "dialog.h"
#include <QtWidgets/QApplication>
#include <QDesktopWidget>
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.setWindowFlags(Qt::FramelessWindowHint);//去掉窗口标题栏
w.show();
//将窗口放置在屏幕靠左,获取屏幕的高-窗体的高除以2.
w.move(((QApplication::desktop()->width()-w.width())*0.25),
(QApplication::desktop()->height()-w.height())>>1);
return a.exec();
}
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include "QMediaPlayer"
#include "QFile" //一个操作文件的输入/输出设备
#include "QDir"
#include "QFileDialog"
#include "QMediaPlaylist"
#include "QTime"
#include <QMessageBox>
#include <QDebug> //测试用
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)//,lrcUi(new Ui::lrcDialog)
{
playList=new QMediaPlaylist;
player =new QMediaPlayer;
ui->setupUi(this);
ui->progressBar->setRange(0,0);//初始化进度条,范围0到0,进度条无法拖动
ui->songList->setColumnWidth(0,200);//初始化歌曲列表的列宽
ui->songList->setRowHeight(0,60);//初始化歌曲列表的行宽
ui->findFrame->hide();//查找窗口默认隐藏
/*
* 播放模式选择的菜单
*/
currentItemInLoop = new QAction(tr("单曲循环"), this);
sequential = new QAction(tr("顺序播放"), this);
loop = new QAction(tr("列表循环"), this);
random = new QAction(tr("随机播放"), this);
model = new QMenu(tr("播放模式"),this);
model->addAction(currentItemInLoop);
model->addAction(sequential);
model->addAction(loop);
model->addAction(random);
playSong= new QAction(tr("播放"), this);
connect(playSong, SIGNAL(triggered()), this, SLOT(on_play_clicked()));
stopSong= new QAction(tr("暂停"), this);
connect(stopSong, SIGNAL(triggered()), this, SLOT(on_play_clicked()));
nextSong= new QAction(tr("下一音乐"), this);
connect(nextSong, SIGNAL(triggered()), this, SLOT(on_nextSong_clicked()));
previousSong= new QAction(tr("上一音乐"), this);
connect(previousSong, SIGNAL(triggered()), this, SLOT(on_firstSong_clicked()));
/*
* 托盘图标的右键菜单
*/
trayIcon = new QSystemTrayIcon(this);
trayMenu = new QMenu(this);
trayIcon->setIcon(QIcon(":/images/tray.png"));
minimizeAction = new QAction(tr("最小化"), this);
connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
quitAction = new QAction(tr("关闭程序"), this);
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
trayMenu->addAction(playSong);
trayMenu->addAction(stopSong);
trayMenu->addAction(nextSong);
trayMenu->addAction(previousSong);
trayMenu->addSeparator();
trayMenu->addMenu(model);
trayMenu->addSeparator();
trayMenu->addAction(minimizeAction);
trayMenu->addAction(quitAction);
trayIcon->show();
trayIcon->setContextMenu(trayMenu);
//托盘图标添加单/双击鼠标相应
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this,SLOT(trayiconActivated(QSystemTrayIcon::ActivationReason)));
/*
* 歌曲列表的右键菜单
*/
songMenu= new QMenu(this);
addSong= new QAction(tr("添加歌曲"), this);
connect(addSong, SIGNAL(triggered()), this, SLOT(on_open_clicked()));
delSong= new QAction(tr("删除歌曲"), this);
connect(delSong, SIGNAL(triggered()), this, SLOT(delMusic()));
clearList= new QAction(tr("清空播放列表"), this);
connect(clearList, SIGNAL(triggered()), this, SLOT(clearMusic()));
songMenu->addAction(playSong);
songMenu->addAction(addSong);
songMenu->addAction(delSong);
songMenu->addAction(clearList);
ui->songList->setContextMenuPolicy(Qt::CustomContextMenu);
//add="D:/QTWLXI/Music1/MUSIC/sor/我们的歌.mp3";// test
//player->setMedia(QUrl::fromLocalFile(add));// test
player->setPlaylist(playList);//设置相应playlist
player->setVolume(100);//设置初始化音量
isSilence=false;//默认不静音
isPlay=false;//默认不播放歌曲
isOpenLyric=true;//默认打开歌词
//进度条改变时播放位置随着改变
connect(ui->progressBar,SIGNAL(sliderMoved(int)),this,SLOT(setPlayerPosition(int)));
//当播放歌曲位置改变时 progressBar设置对应的位置 对应的播放时间与总时间的显示
connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(positionChanged(qint64)));
// 当progressBar改变时 构造歌曲总时间
connect(player, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64)));
//songList 双击播放选中的
connect(ui->songList,SIGNAL(cellDoubleClicked(int,int)),this,SLOT(playto(int,int)));
//显示歌名
connect(playList,SIGNAL(currentIndexChanged(int)),this,SLOT(showSongName(int)));
// connect(playList,SIGNAL(currentIndexChanged(int)),this,SLOT(showLyric(int)));
//播放模式设置
/* 信号无参数的情况下,无法直接给槽传入参数,次方法违背信号与槽参数一致,解决方法在下面
* connect(currentItemInLoop, SIGNAL(triggered()), this, SLOT(setPlayModel(0)));
connect(sequential, SIGNAL(triggered()), this, SLOT( setPlayModel(1)));
connect(loop, SIGNAL(triggered()), this, SLOT( setPlayModel(2)));
connect(random, SIGNAL(triggered()), this, SLOT( setPlayModel(3))); */
//让action响应相应的model槽,让model槽设置相应信号selectedModel的参数在传给setPlayModel
connect(this, SIGNAL(selectedModel(int)), this, SLOT( setPlayModel(int)));
connect(this, SIGNAL(selectedModel(int)), this, SLOT( setPlayModel(int)));
connect(this, SIGNAL(selectedModel(int)), this, SLOT( setPlayModel(int)));
connect(this, SIGNAL(selectedModel(int)), this, SLOT( setPlayModel(int)));
connect(currentItemInLoop, SIGNAL(triggered()), this, SLOT( model0()));
connect(sequential, SIGNAL(triggered()), this, SLOT( model1()));
connect(loop, SIGNAL(triggered()), this, SLOT( model2()));
connect(random, SIGNAL(triggered()), this, SLOT( model3()));
}
void Dialog::model0()
{
emit selectedModel(0);
}
void Dialog::model1()
{
emit selectedModel(1);
}
void Dialog::model2()
{
emit selectedModel(2);
}
void Dialog::model3()
{
emit selectedModel(3);
}
Dialog::~Dialog()
{
delete ui;
}
/*
* 删除歌曲
*/
void Dialog::delMusic(){
static int b=0;
if (QMessageBox::Yes == QMessageBox::question(this,
tr("Question"),
tr("Sure you want to delete this song?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes)) {
int i=ui->songList->currentRow();
playList->clear();
ui->songList->clear();
songName.removeAt(i);
qDebug()<<i<<endl;
QString s = QString::number(i, 10);
for(int j=0;j<songName.length();j++)
ui->songList->setItem(++b, 0, new QTableWidgetItem(s+" "+songName[i]));
ui->strTime->setText("00:00");
QMessageBox::information(this, tr("information"), tr("删除成功"));
} else {
QMessageBox::information(this,tr("information"),tr("取消删除"));
}
}
/*
* 清空列表
*/
void Dialog::clearMusic(){
playList->clear();
ui->songList->clear();
ui->songList->setRowCount(0);
ui->strTime->setText("00:00");
}
/*
* 音量调节
*/
void Dialog::on_volume_sliderMoved(int position)
{
player->setVolume(position);
ui->volume->setValue(position);
if(position==0){
ui->silence->setIcon(QIcon(":/images/silence.png"));
isSilence=true;
}else{
ui->silence->setIcon(QIcon(":/images/nosilence.png"));
isSilence=false;
}
}
/*
* 静音及恢复
*/
void Dialog::on_silence_clicked()
{
isSilence=!isSilence;
if(isSilence)
{
volumeValue=ui->volume->value();
on_volume_sliderMoved(0); //记录静音前的音量
ui->silence->setIcon(QIcon(":/images/silence.png"));
}
else
{
on_volume_sliderMoved(volumeValue);//恢复静音前的音量
ui->silence->setIcon(QIcon(":/images/nosilence.png"));
}
}
/*
* 添加歌曲
*/
void Dialog::on_open_clicked()
{
QString initialName=QDir::homePath();//在window下返回用户(即我的文档)目录
//getOpenFileNames(指定父组件,对话框的标题,默认打开的目录,后缀名过滤器,如果需要使用多个过滤器 使用";;"分割
// ,是默认选择的过滤器,对话框的一些参数设定,比如只显示文件夹等等,)
QStringList pathList=QFileDialog::getOpenFileNames(this, tr("选择文件"), initialName, tr("MP3 Files (*.mp3)"));
//用一个QStringList列表 存放音乐文件的地址,可多选音乐。
for(int i=0; i<pathList.size(); ++i)
{
QString path=QDir::toNativeSeparators(pathList.at(i));//把斜杠转化成反斜杠,获取歌曲的地址
if(!path.isEmpty())
{
playList->addMedia(QUrl::fromLocalFile(path));
//QUrl::fromLocalFile()一定要用这个方法,因为如果文件名或路径有中文或空格,就打不开文件.
//直接用QUrl(fileName)只能打开英文名称和没有空格路径的文件.
QString fileName=path.split("\\").last();//用split 获取文件名(包含后缀) 例 music.mp3
int rownum=ui->songList->rowCount();//行数
ui->songList->insertRow(rownum);//插入空行
QString s = QString::number(ui->songList->rowCount(), 10);
QString Name=fileName.split(".").front();
ui->songList->setItem(rownum, 0, new QTableWidgetItem(s+" . "+Name));
songName.append(Name);
}
}
}
/*
* 下一曲
*/
void Dialog::on_nextSong_clicked()
{
//如果播放列表为空,按钮不可用,直接返回
if(playList->isEmpty())
return;
//如果列表到尽头,则回到列表开头
int currentIndex=playList->currentIndex();
if(++currentIndex==playList->mediaCount())
currentIndex=0;
//设置当前的currentIndex
playList->setCurrentIndex(currentIndex);
isPlay=true;
on_play_clicked();
}
/*
* 上一曲
*/
void Dialog::on_firstSong_clicked()
{
//播放列表为空,按钮不可用,直接返回
if(playList->isEmpty())
return;
//如果列表到开头,则停止播放,直接返回
int currentIndex=playList->currentIndex();
if(currentIndex==0){
isPlay=false;
on_play_clicked();
return;
}
playList->previous();
isPlay=true;
on_play_clicked();
}
/*
* 播放和暂停
*/
void Dialog::on_play_clicked()
{
//如果播放列表为空,按钮不可用,直接返回
if(playList->isEmpty())
return;
isPlay=!isPlay;
if(isPlay)
{ player->pause();
ui->play->setIcon(QIcon(":/images/play.png"));// 暂停时候显示播放图标
ui->play->setToolTip(tr("暂停"));
}
else
{ player->play();
ui->play->setIcon(QIcon(":/images/pause.png"));// 播放时候显示暂停图标
ui->play->setToolTip(tr("播放"));
}
}
/*
* 当进度条改变时,设置歌曲对应的播放位置
*/
void Dialog::setPlayerPosition(int position)
{
player->setPosition(position);
}
/*
* 当播放歌曲位置改变时 progressBar设置对应的位置 对应的播放时间与总时间的显示
*/
void Dialog::positionChanged(qint64 position)//
{
ui->progressBar->setValue(position);//position 单位:毫秒 1000ms=1s
currentTime=new QTime(0,(position/60000)%60,(position/1000)%60);//构造当前时间(小时,分钟,秒和毫秒)。
ui->strTime->setText(currentTime->toString("mm:ss"));//播放时间 输出时间格式09:02(都是两位)
}
/*
* 当progressBar改变时 构造歌曲总时间
*/
void Dialog::durationChanged(qint64 duration)//
{
ui->progressBar->setRange(0,duration);//progressBar的范围从0到duration(总时间)
totalTime=new QTime(0,(duration/60000)%60,(duration/1000)%60);
ui->endTime->setText(totalTime->toString("mm:ss"));//歌曲总时间
}
/*
* 当双击songList时 播放双击的歌曲
*/
void Dialog::playto(int i,int )
{
playList->setCurrentIndex(i);
isPlay=true;
on_play_clicked();
}
/*
* 当前播放歌曲名显示
*/
void Dialog::showSongName(int i)
{
ui->songList->selectRow(i); //播放到这首歌曲的时候选中
QString playtitle=songName[i];
ui->showSongName->setText(playtitle);
}
/*
* 设置播放方式 QMediaPlaylist::PlaybackMode
*/
void Dialog::setPlayModel(int i)
{
switch (i)
{
case 0:
playList->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);//单曲循环
ui->playModel->setIcon(QIcon(":/images/CurrentItemInLoop.png"));
ui->playModel->setToolTip(tr("单曲循环"));
break;
case 1:
playList->setPlaybackMode(QMediaPlaylist::Sequential);//顺序播放
ui->playModel->setIcon(QIcon(":/images/Sequential.png"));
ui->playModel->setToolTip(tr("顺序播放"));
break;
case 2:
playList->setPlaybackMode(QMediaPlaylist::Loop);//列表循环
ui->playModel->setIcon(QIcon(":/images/Loop.png"));
ui->playModel->setToolTip(tr("列表循环"));
break;
case 3:
playList->setPlaybackMode(QMediaPlaylist::Random);//随机播放
ui->playModel->setIcon(QIcon(":/images/Random.png"));
ui->playModel->setToolTip(tr("随机播放"));
break;
}
}
/*
* 模拟标题栏移动消息,使之可以移动
*/
void Dialog::mousePressEvent(QMouseEvent *event)
{
if (ReleaseCapture())
SendMessage(HWND(this->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
event->ignore();
}
/*
* 窗口最小化
*/
void Dialog::on_minWindow_clicked()
{
//系统自定义的最小化窗口函数
showMinimized();
//最大化 showMaximized();
}
/*
* 窗口关闭
*/
void Dialog::on_closeWindow_clicked()
{
//系统自定义的窗口关闭函数
close();
}
/*
* 处理关闭事件
*/
void Dialog::closeEvent(QCloseEvent *event)
{
QMessageBox::StandardButton button;
button = QMessageBox::question(this,tr("Exit the program"),
tr("Do you really want to exit the program"),
QMessageBox::Yes|QMessageBox::No);
if (button == QMessageBox::No) {
event->ignore(); //忽略退出信号,程序继续运行
}
else if (button == QMessageBox::Yes) {
event->accept(); //接受退出信号,程序退出
}
}
/*
* 播放模式的菜单
*/
void Dialog::on_playModel_clicked()
{
QPoint pos(this->x()+47,this->y()+91);//播放模式菜单起点坐标
model->exec(pos);//让播放模式菜单在固定的点显示
}
void Dialog::trayiconActivated(QSystemTrayIcon::ActivationReason reason)
{
if(reason==QSystemTrayIcon::Trigger||QSystemTrayIcon::DoubleClick){
this->showNormal();
this->raise();
}
}
/*
* 歌曲列表右键菜单
*/
void Dialog::on_songList_customContextMenuRequested(const QPoint &pos)
{
songMenu->exec(QCursor::pos());
}
/*
* 显示查找窗口
*/
void Dialog::on_find_clicked()
{
ui->findFrame->show();
}
/*
* 关闭查找窗口
*/
void Dialog::on_close_clicked()
{
ui->findFrame->hide();
}
/*
* 查找功能
*/
void Dialog::on_enter_clicked()
{
QString song=ui->lineEdit->text();
static int a=0;
for(int i=0;i<songName.length();i++){
if(songName[i].contains(song)){
ui->songList->clear();
ui->songList->setItem(a++, 0, new QTableWidgetItem(songName[i]));
}
}
}
/* 方法作废 只能显示LRC的全部内容,无法随时时间只显示歌词
void Dialog::showLyric(int z){
//显示歌词部分
if(isOpenLyric==true)
{
QString str=songName[z];
qDebug()<<songName[z]<<endl;
QFile file("C:\\Users\\k\\Desktop\\musicplayer\\Music3.0\\"+str+".lrc");//
qDebug()<<"C:\\Users\\k\\Desktop\\musicplayer\\Music3.0\\"+str+".lrc"<<endl;
if(!file.open(QIODevice::ReadOnly|QIODevice::Text))
{
QMessageBox::information(this, tr("information"), tr("当前目录下未找到歌词文件"));
}
else
{
QTextStream in(&file);
QString result=in.readAll();
ui->textEdit->setText(result);
}
}
}
void Dialog::on_lyric_clicked()
{
isOpenLyric=!isOpenLyric;
if(isOpenLyric==true){
ui->textEdit->hide();
}else{
ui->textEdit->show();
}
}
*/
void Dialog::on_position_clicked()
{
//TODO 无法使用,无法使当前播放的歌曲被定位
int i=ui->songList->currentRow();
ui->songList->visualRow(i);
}
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include "QDialog"
#include "QtMultimedia"
#include <QCloseEvent>
#include <QMenu>
#include <QSystemTrayIcon>
class QMediaPlaylist;
class QMediaPlayer;
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
signals:
void selectedModel(int);
private slots:
void on_volume_sliderMoved(int position);
void on_silence_clicked();
void on_open_clicked();
void on_nextSong_clicked();
void on_firstSong_clicked();
void on_play_clicked();
void setPlayerPosition(int);
void positionChanged(qint64 position);
void durationChanged(qint64 duration);
void playto(int,int);
void showSongName(int );
void setPlayModel(int);
void on_closeWindow_clicked();//关闭窗口
void on_minWindow_clicked();//最小化窗口
void on_playModel_clicked();
void delMusic();
void clearMusic();
void model0();
void model1();
void model2();
void model3();
void trayiconActivated(QSystemTrayIcon::ActivationReason reason);
void on_songList_customContextMenuRequested(const QPoint &pos);
void on_find_clicked();
void on_close_clicked();
void on_enter_clicked();
//void on_lyric_clicked();
// void showLyric(int);
void on_position_clicked();
private:
Ui::Dialog *ui;
QStringList songName;
QMediaPlayer *player;
QMediaPlaylist *playList;
bool isSilence;
bool isPlay;
bool isOpenLyric;
QTime *currentTime;
QTime *totalTime;
QAction *currentItemInLoop;
QAction *sequential;
QAction *loop;
QAction *random;
QMenu *trayMenu;
QMenu *model;
QSystemTrayIcon *trayIcon;
QAction *playSong;
QAction *stopSong;
QAction *nextSong;
QAction *previousSong;
QAction *quitAction;
QAction *minimizeAction;
QMenu *songMenu;
QAction *addSong;
QAction *delSong;
QAction *clearList;
int volumeValue;
void Dialog::mousePressEvent(QMouseEvent *event);
void closeEvent(QCloseEvent *event);
};
#endif // DIALOG_H