大一下学期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