qt实现MP3的歌曲切换,歌词、进度、模式选择等实现(附源码)

使用的环境:ubuntu16.04,qt5.4.0.
注:写了三天半完成的,使用的线程与进程知识,切歌,显示歌词,控制声量,发送弹幕,查找歌曲,切换桌面背景,模式选择等功能均已实现。但是还是初学者,必然有许多漏洞与不足,希望指正。

部分功能解析:
1.当前时间的获取

QTimer * timer = new QTimer;
timer ->start(1000);
connect(timer,&QTimer::timeout,[=](){
     
//当1秒的时间结束,触发这个槽函数
QDateTime time = QDateTime::currentDateTime();
 //获取当前的时间
QString str = time.toString("yyyy-MM-dd \n hh:mm:ss");             

});

2.mplayer的使用
volume * 1:设置音量的大小
mute 1/0 :设置音量的静音与取消(1为暂停,0为取消)
pause :暂停与继续
seek value :设置快退与快进,取决与value的正负值

  execlp("mplayer","myplayer","-idle","-slave","-quiet","-input","file=./a.txt","1.mp3",NULL);
  //这一个语句就是调用mplayer进程的命令
  //要尽量给其开辟一个新的进程或者是线程,因为其一旦运行,后面的代码就会被取代
  //最后面的哪一个NULL参数不能够被省略
  //每一个参数都有其的含义,可以看到前面两个参数都是mplayer,含义确实不一样地,第一个是可执行文件的名字,由他这个参数去查找命令,第二个参数是命令。

3.字符串的拼接
QString的使用与C++中的string并不是相同的,不能够通过+号来进行凭借(C++中能够直接+号拼接是因为这个+号被重载过了)
那么在qt中的QString怎么拼接呢

			//从lineEdit获得到ui上输入的字符,并把其存放在text中
 			QString text = ui->lineEdit_saysomesthing->text();
            QDateTime time = QDateTime::currentDateTime();
            QString str = time.toString("yyyy-MM-dd  hh:mm:ss");              //获取当前的时间

            QString status = QString(" %1 %2").arg(text).arg(str);//字符串拼接

4.背景图的切换
我采用的是按钮,按钮按下,图片切换

   //按键改变桌面
        connect(ui->table_pushButton,&QPushButton::clicked,[=](){
     
            table_flag++;             // 图片的标志位
            if(table_flag % 3 == 1 )
            //给上图片的路径,这个pixmapPath是一个变量,定义在类中了,所以可以这么直接用上了
            {
     pixmapPath=(":/imag/photo_1.png");}
            else if(table_flag % 3 == 2)
            {
     pixmapPath=(":/imag/photo_2.png");}
           
            //这个updata()是必须要有的,用来更新桌面的背景
            this->update();
        });

5.歌词的切割

//歌词解析
//传入歌曲的名字,得到与之对应的歌词地址
void Widget::Parsing_lyrics(QString)
{
     
    if(lrc.empty() == 0)
    {
     
        lrc.clear();
    }
    char buff[32]="";
    //此时song_name[music_num]的类型是QString类型,需要转换为char * 类型,然后再进行其他的操作,此时获得到的是歌曲文件的地址
    //由于我这个地方偷懒了,把歌曲的名字都改为数字了,如果想要使用,就要自己再想想怎么把歌曲地址通过组包解包,变换为歌词的地址
    //在我这里是将./3.mp3---->./3.rlc
    strcpy(buff,song_name[music_num].toUtf8().data()); //    ./*.mp3

   int n;
   sscanf(buff,"./%d.mp3",&n);
   printf("buff2: %d",n);
   char buff3[32]="";
   sprintf(buff3,"./%d.lrc",n);
    //       ./*.mp3  ------------------>  ./*.lrc
    printf("%s\n",buff3);
    FILE * fp = fopen(buff3,"r");
    if(fp == NULL)
    {
     
        perror("fopen");
    }
    char buff_lrc[128]="";
    while(fgets(buff_lrc,sizeof(buff_lrc),fp) != NULL)
    {
     
        char *p = buff_lrc;
        if(p[1] >= '0' && p[1] <= '9')
        {
     
            char * q = p;
            while(*q == '[')
            {
     
                if(q[10] == ']')
                {
     q += 11;}
                else
                {
     q+=10;}
            }
            while(*p == '[')
            {
     
                int m = 0, n = 0;
                sscanf(p,"[%d:%d",&m,&n);
                this->lrc.insert(m*60+n,q);
                //printf("%d,%s\n",m*60+n,q);
                p+=10;
            }
        }
    }
    fclose(fp);

}

6.自定义信号与槽
信号的来源选择使用emit发送,这个信号必须在类中定义哈,但是不用去实现
自定义的槽函数需要定义,并且实现

这是需要在.h中实现的
signals://这个信号也要自己写哦
    void change_progess(int value);//自定义的信号
private slots://自定义槽函数
    void changeProgess(int value);//自定义的槽函数
发出信号
 emit p->change_progess(rate_of_progress);
 //发出信号,外界接收,从而控制进度的显示
  //获得信号改变进度条      connect(this,SIGNAL(change_progess(int)),this,SLOT(changeProgess(int)));

void Widget::changeProgess(int value)
{
     
    ui->progressBar->setValue(value);
   这个就是槽函数,改变页面上进度条
}

最后效果qt实现MP3的歌曲切换,歌词、进度、模式选择等实现(附源码)_第1张图片

代码如下
.cpp:

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

void * father(void * arg);
void * father2(void * arg);
int gettime_flag;
int change_mode;   //改变模式标志位

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    //创建无名管道
    pipe(fd_pipe);
    //创建有名管道
    int ret2 = mkfifo("./a.txt",0666);
    if(0 == ret2)
    {

        qDebug()<<"创建成功!\n"<setupUi(this);

        change_mode = 0;     //初始化模式为单曲播放模式
        music_num = 0;       //初始化播放曲目
        say_num = 0;         //初始化弹幕,从第0个开始进行滚动播放弹幕
        volume = 70;         //初始化音量
        volume_flat=1;       //静音标志位
        this->pixmapPath=":/imag/photo_1.png"; //初始化桌面
        get_song_name();     //调用该函数,获得所有的歌曲的名字
        get_say();           //调用该函数,获得弹幕的初始化
        table_flag=1;        //初始化桌面壁纸
        gettime_flag=0;      //全局变量,用于按下暂停后记录的标志位,按下暂停后,不再获取时间
        Parsing_lyrics(song_name[music_num]);//加载第一首歌的歌词,解析歌词,把歌词放入map容器中
        this->fd = open("a.txt",O_WRONLY);   //只写打开有名管道




        pthread_t pth3,pth4;
        pthread_create(&pth3,NULL,father,(void *)this);   //创建子线程
        pthread_detach(pth3);//线程分离

        pthread_create(&pth4,NULL,father2,(void *)this);
        pthread_detach(pth4);


        //暂停或者继续
        connect(ui->pause_pushButton,SIGNAL(clicked(bool)),this,SLOT(mystop(void)));
        //杀死子进程,再关闭父进程
        connect(ui->close_pushButton,SIGNAL(clicked(bool)),this,SLOT(myclose(void)));
        //加大声量
        connect(ui->volume_up_pushButton,SIGNAL(clicked(bool)),this,SLOT(turn_up_volume(void)));
        //减小声量
        connect(ui->volume_done_pushButton,SIGNAL(clicked(bool)),this,SLOT(reduce_the_volume(void)));

        //播放下一首
        connect(ui->next_pushButton,SIGNAL(clicked(bool)),this,SLOT(next_music(void)));
        //播放上一首
        connect(ui->before_pushButton,SIGNAL(clicked(bool)),this,SLOT(before_music(void)));



        //查找歌曲功能,lambal表达式
        connect(ui->find_pushButton,&QPushButton::clicked,[=](){
            //获得这一行输入的歌曲名
            QString text = ui->lineEdit->text();

            //qDebug()<<"get lintEdit:"<::iterator it = song_name.begin();
             QVector::iterator ret;
             //在容器中查找有没有这个歌曲的名字,使用迭代器查找
             ret = qFind(song_name.begin(),song_name.end(),text);
             if(ret != song_name.end())
             {
                 QMessageBox::information(this,"yes","find it!");

                 char buff[64]="";
                 sprintf(buff,"loadfile %s\n",text.toUtf8().data());
                 //如果找到了,进行组包之后,发送给有名管道,从而控制mplayer进行播放
                 write(this->fd,buff,strlen(buff));
                 //定义的函数,功能是传入指定的歌曲名字,然后进行歌词的解析,前提是你的文件目录下面得要有哈
                 Parsing_lyrics(song_name[music_num]);
             }
             else
             {
                 QMessageBox::information(this,"sorry","not find it!");
             }
         
        });

        //按键改变桌面
        connect(ui->table_pushButton,&QPushButton::clicked,[=](){
            table_flag++;
            if(table_flag % 12 == 1 )
            //给上图片的路径,这个pixmapPath是一个变量,定义在类中了,所以可以这么直接用上了
            {pixmapPath=(":/imag/photo_1.png");}
            else if(table_flag % 12 == 2)
            {pixmapPath=(":/imag/photo_2.png");}
            else if(table_flag % 12 == 3)
            {pixmapPath=(":/imag/photo_3.png");}
            else if(table_flag % 12 == 4)
            {pixmapPath=(":/imag/photo_4.png");}
            else if(table_flag % 12 == 5)
            {pixmapPath=(":/imag/photo_5.png");}
            else if(table_flag % 12 == 6)
            {pixmapPath=(":/imag/photo_6.png");}
            else if(table_flag % 12 == 7)
            {pixmapPath=(":/imag/photo_7.png");}
            else if(table_flag % 12 == 8)
            {pixmapPath=(":/imag/photo_8.png");}
            else if(table_flag % 12 == 9)
            {pixmapPath=(":/imag/photo_9.png");}
            else if(table_flag % 12 == 10)
            {pixmapPath=(":/imag/photo_10.png");}
            else if(table_flag % 12 == 11)
            {pixmapPath=(":/imag/photo_11.png");}
            //这个updata()是必须要有的,用来更新桌面的背景
            this->update();
        });
        //获得信号改变进度条
        connect(this,SIGNAL(change_progess(int)),this,SLOT(changeProgess(int)));
        //动态显示歌词
        connect(this,SIGNAL(lrc_time(int)),this,SLOT(show_lrc(int)));
        //用定时器获取当前时间并赋给label_time
         QTimer *timer = new QTimer;
         timer->start(5000);
         //每五秒更换一条弹幕
         connect(timer,&QTimer::timeout,[=](){

             if(say_num == (say.size()-1))
             {
                 say_num = 0;

             }
             else
             {
                 say_num++;

             }
				//每隔五秒显示容器里面的内容
             ui->pushButton->setText(say[say_num]);
         });

        //获取从页面上输入的信息,并在后面加上当前的时间,并肩这个两条信息合并,插入到这个弹幕的容器中
         connect(ui->pushButton_say,&QPushButton::clicked,[=](){

            QString text = ui->lineEdit_saysomesthing->text();
            QDateTime time = QDateTime::currentDateTime();

            QString str = time.toString("hh:mm:ss");              //获取当前的时间

            QString status = QString(" %1 %2").arg(text).arg(str);//字符串拼接
            //将拼接的字符串放入容器中
            this->say.push_back(status);
            QMessageBox::information(this,"ok","insert suessful");
            //插入结束了之后,清空lineEdit
            ui->lineEdit_saysomesthing->clear();
         });
    }

}


//父线程用于向子线程发送消息(有名管道),来获得歌曲播放的时间,总时间,以及进度
void * father(void * arg)
{
    Widget * p = (Widget *)arg;
    while(1)
    {
        if(gettime_flag % 2 == 0)
        {
            //printf("father 1 now gettime_flag is :%d\n",gettime_flag);
            write(p->fd,"get_time_pos\n",strlen("get_time_pos\n"));
            usleep(100*100);
            write(p->fd,"get_time_length\n",strlen("get_time_length\n"));
            usleep(100*100);
            write(p->fd,"get_percent_pos\n",strlen("get_percent_pos\n"));
            usleep(100*1000);
        }
        else
        {
            //printf("stop 1\n");
            sleep(1);
        }


    }

}

//通过无名管道,获取歌曲的状态信息
void * father2(void * arg)
{
   Widget * p = (Widget *)arg;
   int time_now,time_all;
   while(1)
   {

           //printf("father 2 now gettime_flag is :%d\n",gettime_flag);

           char buff[64]="";
           read(p->fd_pipe[0],buff,sizeof(buff));
           //printf("this is read son :%s",buff);
           if(strncmp(buff,"ANS_TIME_POSITION",strlen("ANS_TIME_POSITION")) == 0)
           {
               //get time
               sscanf(buff,"ANS_TIME_POSITION=%d",&time_now);
               int minute = time_now / 60;
               int second = time_now % 60;
               char buf_time[32]="";
               sprintf(buf_time,"%02d:%02d",minute,second);
               p->ui->label_time->setText(buf_time);
               emit p->lrc_time(time_now);                   //发出信号,外界接收,从而控制歌词的显示


           }
           if(strncmp(buff,"ANS_LENGTH",strlen("ANS_LENGTH")) == 0)
           {
               //get all time
               sscanf(buff,"ANS_LENGTH=%d",&time_all);
               int minute2 = time_all / 60;
               int second2= time_all % 60;
               char buf_time2[32]="";
               sprintf(buf_time2,"%02d:%02d",minute2,second2);
               p->ui->label_time_all->setText(buf_time2);
               //printf("all time is : %d\n",time_all);
           }
         if(strncmp(buff,"ANS_PERCENT_POSITION",strlen("ANS_PERCENT_POSITION")) == 0)
           {
               int rate_of_progress;
               sscanf(buff,"ANS_PERCENT_POSITION=%d",&rate_of_progress);
               //printf("get rate of progress is %d\n",rate_of_progress);

               emit p->change_progess(rate_of_progress);//发出信号,外界接收,从而控制进度的显示
           }


   }
}




Widget::~Widget()
{
    delete ui;
}
//歌词解析
void Widget::Parsing_lyrics(QString)
{
    if(lrc.empty() == 0)
    {
        lrc.clear();
    }
    char buff[32]="";
    strcpy(buff,song_name[music_num].toUtf8().data()); //    ./*.mp3

   int n;
   sscanf(buff,"./%d.mp3",&n);
   printf("buff2: %d",n);
   char buff3[32]="";
   sprintf(buff3,"./%d.lrc",n);
    //       ./*.mp3  ------------------>  ./*.lrc
    printf("%s\n",buff3);
    FILE * fp = fopen(buff3,"r");
    if(fp == NULL)
    {
        perror("fopen");
    }
    char buff_lrc[128]="";
    while(fgets(buff_lrc,sizeof(buff_lrc),fp) != NULL)
    {
        char *p = buff_lrc;
        if(p[1] >= '0' && p[1] <= '9')
        {
            char * q = p;
            while(*q == '[')
            {
                if(q[10] == ']')
                {q += 11;}
                else
                {q+=10;}
            }
            while(*p == '[')
            {
                int m = 0, n = 0;
                sscanf(p,"[%d:%d",&m,&n);
                this->lrc.insert(m*60+n,q);
                //printf("%d,%s\n",m*60+n,q);
                p+=10;
            }
        }
    }
    fclose(fp);

}


//静态插入所有的歌曲的位置
void Widget::get_song_name(void)
{
    this->song_name.push_back("./1.mp3");
    this->song_name.push_back("./2.mp3");
    this->song_name.push_back("./3.mp3");
    this->song_name.push_back("./4.mp3");
    this->song_name.push_back("./5.mp3");
    this->song_name.push_back("./6.mp3");
    this->song_name.push_back("./7.mp3");
    this->song_name.push_back("./8.mp3");
    this->song_name.push_back("./9.mp3");
    this->song_name.push_back("./10.mp3");
    this->song_name.push_back("./11.mp3");
    this->song_name.push_back("./12.mp3");
    this->song_name.push_back("./13.mp3");

}
//静态插入弹幕的消息
void Widget::get_say()
{
    this->say.push_back("虽然只能输入英文");
    this->say.push_back("有弹幕发就好");
    this->say.push_back("虽然是滚动的");
    this->say.push_back("但是,暂且就当这是一个功能吧");
    this->say.push_back("将就着用吧");
    this->say.push_back("周继是一个大帅逼!");
    this->say.push_back("周继是一个大帅逼!!");
    this->say.push_back("周继是一个大帅逼!!!");
    this->say.push_back("周继是一个大帅逼!!!!");
}

void Widget::paintEvent(QPaintEvent *ev)
{
    //绘制背景图
    //定义一个画家QPainter
    QPainter *p = new QPainter(this);//在主窗口上画图
    //定义图片对象
    QPixmap pix;
    //pix加载一张图片
    pix.load(this->pixmapPath);
    //修改图片大小
    pix.scaled(this->width(), this->height());
    //画家花背景图
    p->drawPixmap(0,0,this->width(), this->height(), pix);
}

void Widget::mystop(void)
{
    //暂停或者播放

    write(this->fd,"pause\n",strlen("pause\n"));
    gettime_flag++;
    //printf("pause now gettime_flag is :%d\n",gettime_flag);
    //printf("写入管道字节数:%ld\n",write_num);
}
//杀死子进程,然后关闭父进程
void Widget::myclose(void)
{
    //kill son

    kill(0,9);
    this->close();
}
//加声量
void Widget::turn_up_volume(void)
{
    if(this->volume >= 100)
    {
        //printf("sorry,The current volume is at maximum\n");
         qDebug()<<"sorry,The current volume is at maximum"<volume +=5;
        //int fd = open("a.txt",O_WRONLY);
        char buff[64]="";
        sprintf(buff,"volume %d 1\n",this->volume);
        write(this->fd,buff,strlen(buff));

    }
}
//减声量
void Widget::reduce_the_volume(void)
{
    if(this->volume <= 0)
    {
        printf("sorry,The current sound volume is at a minimum\n");
        QMessageBox::information(this,"sorry","This is the minimum volume!");
    }
    else
    {
        this->volume -= 5;
        //int fd = open("a.txt",O_WRONLY);
        char buff[64]="";
        sprintf(buff,"volume %d 1\n",this->volume);
        ssize_t write_num = write(this->fd,buff,strlen(buff));
        printf("写入管道:%s\n",buff);
    }
}
//下一曲
void Widget::next_music(void)
{
    if(music_num == song_name.size()-1)
    {
        printf("All the songs have been played\n");
        QMessageBox::information(this,"sorry","this is lost one!");
    }
    else
    {


        music_num++;
        Parsing_lyrics(song_name[music_num]);
        //int fd = open("a.txt",O_WRONLY);
        char buff[64]="";
        printf("now song is :%s\n",song_name[music_num].toUtf8().data());
        sprintf(buff,"loadfile %s\n",song_name[music_num].toUtf8().data());

        write(this->fd,buff,strlen(buff));

    }

}
//上一曲
void Widget::before_music(void)
{
    if(music_num == 0)
    {
        printf("You can't go any further because this is the last song\n");
        QMessageBox::information(this,"sorry","this is lost one!");
    }
    else
    {
        music_num--;
         Parsing_lyrics(song_name[music_num]);
        //int fd = open("a.txt",O_WRONLY);
        char buff[64]="";
        printf("now song is :%s\n",song_name[music_num].toUtf8().data());
        sprintf(buff,"loadfile %s\n",song_name[music_num].toUtf8().data());

        write(this->fd,buff,strlen(buff));
    }

}
//根据获取时间信号来的动态控制歌词展示
void Widget::show_lrc(int values)
{
    QFont ft;
    ft.setPointSize(12);
    ui->label_lrc_one->setFont(ft);

    ui->label_lrc_two->setFont(ft);

    QMap::iterator it = lrc.begin();
    for(;it != lrc.end();it++)
    {
        if(it.key() == values)
        {
            ui->label_lrc_one->setText(lrc[values]);
            if(lrc.upperBound(values).key() != lrc.end().key())
            {
                ui->label_lrc_two->setText(lrc.upperBound(values).value());
            }
        }
    }
}
//静音按钮(这个是转到槽,没有用connect进行连接)
void Widget::on_novolume_pushButton_clicked()
{
    if(this->volume_flat % 2 == 1)
    {
        write(this->fd,"mute 1\n",strlen("mute 1\n"));

    }
    else if(this->volume_flat % 2== 0)
    {
        write(this->fd,"mute 0\n",strlen("mute 0\n"));
    }
    this->volume_flat++;
}
//更改进度条的槽函数
void Widget::changeProgess(int value)
{
    //响应进度到100时,切换歌曲,且只能切换一次
    //设置随机数种子
    srand(time(NULL));
    ui->progressBar->setValue(value);
    if(100 == value )
    {

        if(0 == change_mode)
        {
            printf("单曲播放模式,歌曲结束,等待切换下一首\n");

        }
        if(1 == change_mode)
        {
            printf("单曲循环模式\n");
            char buff[64]="";
            sprintf(buff,"loadfile %s\n",song_name[music_num].toUtf8().data());
            write(this->fd,buff,strlen(buff));

        }
        if(2 == change_mode)
        {
            printf("顺序播放模式\n");
            music_num++;
            Parsing_lyrics(song_name[music_num]);
            char buff[64]="";
            printf("now song is :%s\n",song_name[music_num].toUtf8().data());
            sprintf(buff,"loadfile %s\n",song_name[music_num].toUtf8().data());

            write(this->fd,buff,strlen(buff));
        }
        if(3 == change_mode)
        {
            printf("随机播放模式\n");
            music_num = rand()%13+1;
            Parsing_lyrics(song_name[music_num]);
            char buff[64]="";
            printf("now song is :%s\n",song_name[music_num].toUtf8().data());
            sprintf(buff,"loadfile %s\n",song_name[music_num].toUtf8().data());

            write(this->fd,buff,strlen(buff));
        }

        usleep(500 * 1000);      //防止一直切换,100这个值会接受到多次

    }
}

void Widget::on_comboBox_currentIndexChanged(int index)
{
    if(0 == index)
    {
        printf("单曲播放模式\n");
    }
    if(1 == index)
    {
        printf("单曲循环模式\n");
    }
    if(2 == index)
    {
        printf("顺序播放模式\n");
    }
    if(3 == index)
    {
        printf("随机播放模式\n");
    }
  change_mode = index;
}

.h:

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 
#include 
#include 
namespace Ui {
     
class Widget;
}

class Widget : public QWidget
{
     
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    int volume;                    //音量
    QVector<QString> song_name;    //存放所有的歌曲的名字
    // say something
    QVector<QString> say;          //存放弹幕的容器
    //lrc
    QMap<int,QString> lrc;         //存放歌词的容器

    void Parsing_lyrics(QString);  //歌词解析

    int music_num;
    int say_num;
    void get_song_name(void);
    void get_say(void);
    int fd;
    int volume_flat;
    void paintEvent(QPaintEvent *ev);//重写画家事件
    int fd_pipe[2];
    QString pixmapPath;

    int flag;
    int table_flag;


    Ui::Widget *ui;
public slots:

    void mystop(void);

    void myclose(void);
    void turn_up_volume(void);
    void reduce_the_volume(void);
    void next_music(void);
    void before_music(void);
    //歌词显示
    void show_lrc(int values);
private slots:
    void on_novolume_pushButton_clicked();
    void changeProgess(int value);
    void on_comboBox_currentIndexChanged(int index);

signals:
    void change_progess(int value);
    void lrc_time(int value);
private:


};

#endif // WIDGET_H

界面文件

qt实现MP3的歌曲切换,歌词、进度、模式选择等实现(附源码)_第2张图片

你可能感兴趣的:(使用qt完成MP3功能,qt,c语言,c++)