C++ QT 音乐播放器

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

 

posted @ 2016-04-08 12:43  郁闷紫番薯  阅读(5189)  评论(0编辑  收藏  举报