欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于QT实现Mp3播放器(代码部分)

程序员文章站 2022-05-22 19:55:22
...

前言

    最近有一个课程实验,利用window上的API接口实现MP3播放器。 突发奇想,在linux下用相关接口做一个MP3播放器。最先的打算是完全使用纯C写的,但后来感觉编写调试实在费劲。于是就使用了QT这个IDE工具,还可以编写个图形界面的。这篇博客主要贴代码,理论部分,请参见我的另一篇博客(基于QT实现Mp3播放器(理论部分))
    来,小二,上个图(注重逻辑,界面并没有认真规划,⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄)。
基于QT实现Mp3播放器(代码部分)

实现代码

playerprocess.cpp

#include "playerprocess.h"
#include<QDebug>

PlayerProcess::PlayerProcess(QObject *parent) : QObject(parent)
{
    process = NULL;
}




//播放Mp3文件
void PlayerProcess::play(QString mp3_file)
{
    if(mp3_file.isEmpty() == false)
    {
        QString play_tool = "mplayer";      //利用mplayer工具进行播放
        QStringList argus;

        process = new QProcess();   //每次新生成一个播放进程

        //以下是播放时的参数
        argus<<"-slave";
        argus<<"-quiet";
        argus<<mp3_file;

        //开始播放
        process->start(play_tool,argus);

        if(process->waitForStarted(5000) == false)       //等待播放进程开始
            qDebug()<<"fail to pause or replay the player";
    }
    else
        qDebug()<<"file name is empty!!!";

}
//暂停
void PlayerProcess::Pause()
{
    process->write("pause\n");      //利用mplayer提供的借口,向进程写入参数
}
//重新开始
void PlayerProcess::Rebegin()
{
    process->write("pause\n");   //利用mplayer提供的借口,向进程写入参数
}


//加音量:
void PlayerProcess::Up(int volume)
{

    QString cmd = "volume " + QString::number(volume)+" 2 \n";  //利用mplayer提供的借口,向进程写入参数
    process->write(cmd.toUtf8());
}

//减音量
void PlayerProcess::Down(int volume)
{

    QString cmd = "volume " + QString::number(volume)+" 2 \n";  //利用mplayer提供的借口,向进程写入参数
    process->write(cmd.toUtf8());
}


//结束当前播放进程
void PlayerProcess::End()
{
    if(process != NULL)      //判断是否是自动播放完毕停止,还是手动更换曲目停止
    {
        QStringList args;

        process->kill();             //kill 当前进程
        if(process->waitForFinished(5000) == false)           //等待进程结束
        {
            qDebug()<<"fail to kill the last song";
        }
        else
        {
            delete process;
            qDebug()<<"kill the last song";
        }

    }

}

//获取播放进程
QProcess* PlayerProcess::GetProcess()
{
    return process;
}

//设置播放进程
void PlayerProcess::SetProcess(QProcess * process)
{
    this->process = process;
}

player.cpp

#include "player.h"

#include <QDebug>

Player::Player(QObject *parent) : QObject(parent)
{
    volume = 50;        //初始化音量为50.音量范围为0-100

    status = Player::InitStatus ;         //初始化状态

    cur_song = -2;      //init status
}

PlayerProcess* Player::GetPlaPro()
{
    return &playerprocess;
}

//返回当前播放器状态
Player::PlayStatus Player::GetPlaySta()
{
    return status;
}


//判断一个状态是否正常定义(仅限枚举变量底层用连续int实现)
bool Player::IsIncInPlaySta(PlayStatus sta)
{
    if(sta >= Player::InitStatus && sta<= Player::PauseStatus )
        return true;
    else
        return false;
}

//设置播放器状态
void Player::SetPlaySta(PlayStatus sta)
{
    if(IsIncInPlaySta(sta))
        status = sta;
    else
        qDebug()<<"player status is invalid";
}

//设置当前歌曲
void Player::SetCurSong(int index)
{
    if(index >= -1 && index <= song_list.size())        //-1代表下一次播放从最后一首开始。song_lise.size()代表下一次播放从头开始
        cur_song = index;
    else
        qDebug()<<"player index is invalid";
}

//获得播放器歌曲
int Player::GetCurSong()
{
    return cur_song;
}


//设置歌曲列表
void Player::SetSongList(QStringList list)
{
    if(list.empty() == false)
        song_list = list;
}

//添加歌曲到列表
void Player::AddSongToList(QStringList add_songs)
{
    if(add_songs.empty() == false)
        song_list.append(add_songs);
}

//获取歌曲列表
QStringList Player::GetSongList()
{
    return song_list;
}

//删除歌曲
void Player::DelSong(int index)
{
    if(index >= 0 && index <= song_list.size()-1)
    {
        song_list.removeAt(cur_song);
    }
}

//删除当前歌曲
void Player::DelCurSong()
{
    DelSong(cur_song);
}

//加音量
void Player::Up()
{
    if(volume < 100)
    {
        volume+=10;
        playerprocess.Up(volume);
    }

}
//减音量
void Player::Down()
{
    if(volume > 0)
    {
        volume-=10;
        playerprocess.Down(volume);
    }
}


//重新开始一个播放
void Player::NewPlay()
{
    if(song_list.size() == 0)        //若歌曲列表为空
    {
        qDebug()<<"song list is empty";
        return ;
    }
    else
    {
        if(cur_song == -1)       //若是第一首(0开始)以前的歌曲,就循环到歌曲列表的最后一首
            cur_song = song_list.size()-1;
        else if(cur_song == -2 || cur_song == song_list.size())      //若是超过最后一首,则回到第一首(0开始)
            cur_song = 0;

    }

    QString play_song = song_list.at(cur_song);   //获得歌曲列表内容

    playerprocess.play(play_song);         //播放


}

//播放歌曲
void Player::Play()
{
   if(status == Player::InitStatus)      //初始状态
   {
        NewPlay();          //一个新的播放任务开始
        status = Player::RunningStatus;  //设置为运行状态
   }
   else if(status == Player::RunningStatus)      //若是运行状态
   {
          playerprocess.Pause();           //暂停
          status = Player::PauseStatus;  //设置为运行状态
   }
   else
   {
       playerprocess.Rebegin();       //重新开始
       status = Player::RunningStatus; //设置为运行状态

   }

}

//下一曲
void Player::Next()
{
    if(cur_song == -2)      //init status
        cur_song = 0;
    else
        ++cur_song;

}

// 上一曲
void Player::Pre()
{
    if(cur_song == -2)      //init status
        cur_song = 0;
    else
        --cur_song;

}

//kill当前播放进程
void Player::End()
{
    playerprocess.End();
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include<QFileDialog>
#include<QDebug>


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

    InitWindow();       //初始化窗口
}

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

//初始化窗口:大小、颜色、背景等
void Widget::InitWindow()
{
    setWindowTitle("EasyMp3Player");

    setFixedSize(this->width(),this->height());

    //设置背景
    QPalette PAllbackground = this->palette();
    QImage ImgAllbackground(":/back.png");
    QImage fitimgpic=ImgAllbackground.scaled(this->width(),this->height(), Qt::IgnoreAspectRatio);
    PAllbackground.setBrush(QPalette::Window, QBrush(fitimgpic));
    this->setPalette(PAllbackground);


    QFont item_font;
    item_font.setPixelSize(50);
    item_font.setBold(true);

    ui->listWidget->setStyleSheet("background-color:transparent; QListWidget::item(color:black)");
}

//高亮选中的歌曲栏目
void Widget::HighLigCurSong()
{
    int cur_song = player.GetCurSong() ;
    QStringList song_list = player.GetSongList();

    if(cur_song>=0 && cur_song <= song_list.size()-1)
    {
        QListWidgetItem * tmp =  ui->listWidget->item(cur_song);
        tmp->setBackgroundColor(QColor("orange"));        //当前播放歌曲高亮
    }

}

//显示歌曲列表
void Widget::ShowSongList()
{
    ui->listWidget->clear();

    QStringList songs;
    QStringList song_list = player.GetSongList();
    foreach (QString song_dir, song_list)
    {
        songs.append(QFileInfo(song_dir).fileName());
    }

    ui->listWidget->addItems(songs);

    HighLigCurSong();   //高亮

}

//点击播放按钮
void Widget::on_pushButton_play_clicked()
{
    Player::PlayStatus status = player.GetPlaySta();

    player.Play();  //播放歌曲
    if(status == Player::InitStatus)
        ConnectNewProcess();        //连接新的player进程到自动播放结束槽

    //关联每个播放进程结束信号和槽
   ShowSongList();          //在QListWidget中显示歌曲列表

}

//下一曲
void Widget::on_pushButton_next_clicked()
{

    Player::PlayStatus status = player.GetPlaySta();

    if(status == Player::RunningStatus)
        player.End();

    player.Next();       //下一曲

    player.SetPlaySta(Player::InitStatus);  //回到初始状态

    on_pushButton_play_clicked();

}

//上一曲
void Widget::on_pushButton_pre_clicked()
{
    Player::PlayStatus status = player.GetPlaySta();

    if(status == Player::RunningStatus)     //是否是从运行状态点击上一曲
        player.End();

    player.SetPlaySta(Player::InitStatus);      //回到初始状态
    player.Pre();        //上一曲
    on_pushButton_play_clicked();

}

//添加歌曲到播放列表
void Widget::on_pushButton_Add_clicked()
{
    QStringList file_names = QFileDialog::getOpenFileNames(this,tr("choose a song"),".","music(*.mp3)");

    player.AddSongToList(file_names);
    ShowSongList();         //show song list
}

//删除当前歌曲
void Widget::on_pushButton_del_clicked()
{

    player.DelCurSong();        //删除当前歌曲

    ShowSongList();
    player.End();       //结束当前播放歌曲

    player.SetPlaySta(Player::InitStatus);
    on_pushButton_play_clicked();

}


//加音量
void Widget::on_pushButton_up_clicked()
{
    player.Up();
}

//减音量
void Widget::on_pushButton_down_clicked()
{
    player.Down();
}

 //连接新的player进程到自动播放结束槽
bool Widget::ConnectNewProcess()
{
    QProcess * tmp = player.GetPlaPro()->GetProcess();
    if(tmp != NULL)
    {
        connect(tmp ,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(PlayEnd(int,QProcess::ExitStatus)));
        return true;
    }
    else
    {
        qDebug()<<"connect new player process failed";
        return false;
    }
}

//一首歌曲自动播放结束
void Widget::PlayEnd(int code, QProcess::ExitStatus exit_status)
{
    if(exit_status == QProcess::NormalExit)     //正常退出(注意:切换下一曲、上一曲为播放进程为非正常退出)
    {

        player.GetPlaPro()->SetProcess(NULL);   //设置为空
        on_pushButton_next_clicked();       //下一曲
        ShowSongList();     //显示列表
    }

}

//程序退出,把所有的播放进程删除
void Widget::closeEvent(QCloseEvent *event)
{
    player.End();
}

//退出
void Widget::on_pushButton_Quit_clicked()
{
    close();
}

   具体的代码都比较简单,注释也相对详细。这里只说一个点(不关心的可以略过)。如下
当前歌曲播放完毕之后需要切换下一首,因为是每次使用QProcess新进程播放音乐,所以主进程和播放的进程相对独立,这样的话就必须在新建QProcess进程时connect播放进程的退出状态到具体的槽(在这个槽中进行新建下一个播放进程,否则达不到自动切换的目的,同时也为了更改(高亮)下一首歌曲)。
问题是如果使用上述分层的设计按理说,这部分connect的代码应该放在player这层中,但是player是做为一个widget的一个对象,这样的话,就没法调用包括ShowSongList()的槽。 这个问题想了很久,尝试了很多方法,还是不太满意。最后只能把connect连接放在widget中实现了。

后言

具体的工程代码已经打包了,有需要的请到对应的资源页进行下载。