首页 > 代码库 > 编程练习:MP3播放器

编程练习:MP3播放器

功能介绍:

MP3播放器

构思过程:满足基本的播放要求(播放/暂停,快进,快退),带有歌词显示,标签显示,带曲目列表,支持中文

用到的工具(平台:Windows XP SP3):

编程语言:C++

图标制作:Photo shop

音频文件标签库:mediaInfo(第三方库)

标签编码转换:sqlite3数据库及sqlite3 C++库(提前已经将对应的unicode和gbk编码用C++录入sqlite3数据库,过程如果遇到需要,则直接查表调用即可)


文件目录:

程序运行界面:

初始状态


添加多个文件状态

列表横向摆放


主要代码部分

/*
 *功能: 音频播放器
 *作者: KAKASI (gongsunyongwu@163.com)
 *时间: 2014-6-1
 *版本: V1.0
 *
 */

#include "musicPlayer.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QPixmap>
#include <QBitmap>
#include <QPainter>
#include <QIcon>
#include <QFile>
#include <QTextStream>
#include <QPushButton>
#include <QMediaMetaData>
#include <QDebug>
#include <QLibrary>
#include <stdio.h>
#include <QFileInfo>
#include <QFileDialog>
#include <QLocale>
#include <iostream>
#include <QByteArray>
#include <iostream>
#include <QByteArray>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <bitset>
#include <iomanip>
#include <QTextCodec>
#include "QMediaInfo.h"

using namespace std;
#define cout qDebug()

MusicPlayer::MusicPlayer(QWidget *parent)
    :QWidget(parent)
{
    //some information init
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
    isMouseDown = false;
    QPushButton *listBtn = new QPushButton("L");
    listBtn->setMaximumSize(20,20);
    connect(listBtn, SIGNAL(clicked()), SLOT(showList()));
    listBtn->setStyleSheet("background:gray");
    QPushButton *loadBtn = new QPushButton("O");
    loadBtn->setMaximumSize(20,20);
    connect(loadBtn, SIGNAL(clicked()), SLOT(loadMusics()));
    loadBtn->setStyleSheet("background:gray");
    QPushButton *minBtn = new QPushButton("-");
    minBtn->setMaximumSize(20,20);
    connect(minBtn, SIGNAL(clicked()), SLOT(setMin()));
    minBtn->setStyleSheet("background:gray");
    QPushButton *exitBtn = new QPushButton("X");
    exitBtn->setMaximumSize(30,20);
    connect(exitBtn, SIGNAL(clicked()),SLOT(close()));
    exitBtn->setStyleSheet("background:gray; text-align:top");
    QHBoxLayout *titleLayout = new QHBoxLayout;
    titleLayout->addStretch();
    titleLayout->addWidget(listBtn,0,Qt::AlignTop);
    titleLayout->addWidget(loadBtn,0,Qt::AlignTop);
    titleLayout->addWidget(minBtn,0,Qt::AlignTop);
    titleLayout->addWidget(exitBtn,0,Qt::AlignTop);
    titleLayout->setSpacing(0);
    titleLayout->setContentsMargins(0, 0, 0, 0);


    //layout
    musicNameLabel = new MyLabel();
    musicNameLabel->setMinimumWidth(200);
    musicNameLabel->setText("Take Me Away");
    musicNameLabel->setStyleSheet("font-size:23px; font-family: 隶书; color:white");

    authorLabel = new MyLabel();
    authorLabel->setText("Avril");
    authorLabel->setStyleSheet("font-size:14px; font-family:隶书; color:white");

    timeLabel = new MyLabel();
    totalTime = 302;
    timeLabel->setText(tr("T: <span style='color:Coral'>%1</span> / %2").arg(getTimeStr(0)).arg(getTimeStr(totalTime)));
    timeLabel->setStyleSheet("font-size:14px; font-family:隶书;color:white");

    volLabel = new MyLabel;
    volLabel->setText(tr("V:%1").arg("30%"));
    volLabel->setStyleSheet("font-size:14px; font-family:隶书; color:white");

    QHBoxLayout *timeAndVolLabel = new QHBoxLayout;
    timeAndVolLabel->addWidget(volLabel);
    timeAndVolLabel->addStretch();
    timeAndVolLabel->addWidget(timeLabel);

    prevLabel = new MyLabel;
    playOrPauseLabel = new MyLabel;
    nextLabel = new MyLabel;

    connect(playOrPauseLabel, SIGNAL(clicked()), SLOT(playOrPause()));
    connect(nextLabel, SIGNAL(clicked()), SLOT(next()));
    connect(prevLabel, SIGNAL(clicked()), SLOT(prev()));

    QPixmap img1("images/prev3.png");
    QPixmap img2("images/play.png");
    QPixmap img3("images/next3.png");
    prevLabel->setPixmap(img1.scaled(40,40));
    playOrPauseLabel->setPixmap(img2.scaled(60,60));
    nextLabel->setPixmap(img3.scaled(40,40));

    prevLabel->resize(40,40);
    playOrPauseLabel->resize(60,60);
    nextLabel->resize(40,40);


    prevLabel->setStyleSheet("border-style:flat;");
    playOrPauseLabel->setStyleSheet("border-style:flat");
    nextLabel->setStyleSheet("border-style:flat");

    QString smallStyleStr = "width:40px; height:40px; ";
    QString bigStyleStr = "width:60px; height:60px; ";
    prevLabel->setStyleSheet(smallStyleStr);
    playOrPauseLabel->setStyleSheet(bigStyleStr);
    nextLabel->setStyleSheet(smallStyleStr);

    picLabel = new MyLabel();
    picLabel->resize(85,85);
    picLabel->setStyleSheet("margin-left:6px;margin-right:10px;");
    QPixmap pic("images/logo.png");
    picLabel->setPixmap(pic);
    QHBoxLayout *picLayout = new QHBoxLayout;
    picLayout->addWidget(picLabel);

    space = new MyLabel;
    space->setText("<hr>");
    currentLRC = new MyLabel("<center> </center>");
    currentLRC->setStyleSheet("font-size:25px; font-family:隶书;color:DeepSkyBlue;");
    nextLRC = new MyLabel("<center> </center>");
    nextLRC->setStyleSheet("font-size:15px; font-family:隶书; color:LightGrey;");

    progressSlider = new QSlider(Qt::Horizontal);
    progressSlider->setRange(0,totalTime);
    connect(progressSlider, SIGNAL(sliderMoved(int)), SLOT(setPosition(int)));
    connect(progressSlider, SIGNAL(sliderReleased()), SLOT(setPosition()));
    volSlider = new QSlider(Qt::Horizontal);
    volSlider->setRange(0,100);
    volSlider->setValue(30);
    connect(volSlider, SIGNAL(valueChanged(int)), SLOT(changeVol(int)));
    QFile file("qss/style1.qss");
    file.open(QFile::ReadOnly);
    volSlider->setStyleSheet(file.readAll());
    file.close();
    file.setFileName("qss/style2.qss");
    file.open(QFile::ReadOnly);
    progressSlider->setStyleSheet(file.readAll());
    progressSlider->setMinimumWidth(240);

    QHBoxLayout *slider = new QHBoxLayout;
    slider->addWidget(volSlider);
    slider->addStretch();
    slider->addWidget(progressSlider);

    QVBoxLayout *midLayout = new QVBoxLayout();
    midLayout->addWidget(musicNameLabel);
    midLayout->addWidget(authorLabel);
    midLayout->addLayout(timeAndVolLabel);

    QHBoxLayout *operationLayout = new QHBoxLayout();
    operationLayout->addWidget(prevLabel, 0,Qt::AlignRight);
    operationLayout->addWidget(playOrPauseLabel, 0, Qt::AlignRight);
    operationLayout->addWidget(nextLabel, 0, Qt::AlignRight);

    QHBoxLayout *topLayout = new QHBoxLayout;
    topLayout->addLayout(midLayout);
    topLayout->addLayout(operationLayout);

    QVBoxLayout *rightLayout = new QVBoxLayout;
    rightLayout->addLayout(topLayout);
    rightLayout->addLayout(slider);

    QVBoxLayout *lrcLayout = new QVBoxLayout;
    lrcLayout->addWidget(currentLRC);
    lrcLayout->addWidget(nextLRC);

    QHBoxLayout *mainLayout1 = new QHBoxLayout();
    mainLayout1->addLayout(picLayout);
    mainLayout1->addLayout(rightLayout);

    QVBoxLayout *mainLayout2 = new QVBoxLayout();
    mainLayout2->addLayout(titleLayout);
    mainLayout2->addLayout(mainLayout1);
    mainLayout2->addWidget(space);
    mainLayout2->addLayout(lrcLayout);
    mainLayout2->setSpacing(0);
    mainLayout2->setContentsMargins(5,0,15,15);
    this->setLayout(mainLayout2);
    this->resize(this->sizeHint()); //important for setRounded(bool)
    setAttribute(Qt::WA_TranslucentBackground, true);
    setRounded(true);
    isPlaying = false;

    listUi = 0;

    list = new QStringList;
    playerList = new QMediaPlaylist;
    playerList->setCurrentIndex(0);
    playerList->setPlaybackMode(QMediaPlaylist::Loop);

    player = new QMediaPlayer;
    player->setPlaylist(playerList);
    connect(player,SIGNAL(positionChanged(qint64)), SLOT(positionChange(qint64)));
    connect(player,SIGNAL(durationChanged(qint64)), SLOT(durationChange(qint64)));
    volSlider->setValue(player->volume());
    createActions();



    lrc = new QMap<int,QString>;

    updateInfo();
}

void MusicPlayer::closeEvent(QCloseEvent *event)
{
    if (listUi != 0)
        listUi->close();
    event->accept();
}

//显示曲目列表
void MusicPlayer::showList()
{
    if (listUi == 0)
    {
        listUi = new MediaList(this->sizeHint(), this->pos(), this);
        listUi->show();
        return;
    }
    if (listUi->isHidden())
    {
        listUi->show();
    }
    else
    {
        listUi->hide();
    }
}

//打开音频文件
void MusicPlayer::loadMusics()
{
    QStringList files = QFileDialog::getOpenFileNames(
                            this,
                            "Select one or more files to open",
                            "/home",
                            "musics (*.mp3 *.wma *.wav)");
    int begin = list->length();
    if (!files.isEmpty())
    {
        QString str;
        foreach (str, files)
        {
            list->append(str);
            playerList->addMedia(QUrl::fromLocalFile(list->last()));
        }
        playerList->setCurrentIndex(begin);
        updateInfo();
        if (listUi == 0)
        {
            listUi = new MediaList(this->sizeHint(), this->pos(), this);
        }
        if (listUi != 0)
        {
            listUi->addFiles(files);
        }
    }
    //歌词初始化
    initLrc();
    player->play();
    QPixmap img(("images/pause.png"));

    playOrPauseLabel->setPixmap(img.scaled(60,60));
}

//任意区域右键菜单
void MusicPlayer::contextMenuEvent(QContextMenuEvent *event)
{
    menu->clear();
    menu->addAction(openAction);
    menu->addAction(exitAction);

    menu->exec(QCursor::pos());
    event->accept();
}

//
void MusicPlayer::createActions()
{
    menu = new QMenu(this);
    openAction = new QAction("open",this);
    exitAction = new QAction("exit",this);
}

//更新界面信息
void MusicPlayer::updateInfo()
{
    QString title;
    QString author;
    QFileInfo f;
    if (!list->empty())
    {
        QString fileName = list->at(playerList->currentIndex());
        info = new QMediaInfo(fileName);
        f.setFile(fileName);
        if (f.suffix().toUpper() == "MP3")
        {
            title = info->getInfo("Title",true);
            author = info->getInfo("Performer",true);
        }
        else
        {
            title = info->getInfo("Title");
            author = info->getInfo("Performer");
        }
        title = f.baseName();
        //cout << title << author;
        delete info;

    }
    title.truncate(8);
    if (title.length() > 8)
        title += "..";

    if (title.isEmpty())
        title = "Title:Unknown";
    if (author.isEmpty())
        author = "Author:Unknown";

    musicNameLabel->setText(title);
    authorLabel->setText(author);

    curLrc = "";
    nextLrcStr = "";
    currentLRC->setText("<center>" + curLrc +"</center>");
    nextLRC->setText("<center>" + nextLrcStr +"</center>");
    //歌词初始化
    initLrc();
}

//下一首
void MusicPlayer::next()
{
    playerList->next();
    //qDebug()<<playerList->currentIndex();
    updateInfo();
    //歌词初始化
    initLrc();
}

//上一首
void MusicPlayer::prev()
{
    playerList->previous();
    updateInfo();
    //歌词初始化
    initLrc();
}

//时间更新
void MusicPlayer::durationChange(qint64 duration)
{
    totalTime = duration;
    progressSlider->setRange(0, duration);
    timeLabel->setText(tr("T: <span style='color:Coral'>%1</span> / %2").arg(getTimeStr(0)).arg(getTimeStr(totalTime)));
}

//进度更新
void MusicPlayer::positionChange(qint64 pos)
{
    if (!progressSlider->isSliderDown())
        progressSlider->setValue(pos);
    timeLabel->setText(tr("T: <span style='color:Coral'>%1</span> / %2").arg(getTimeStr(pos)).arg(getTimeStr(totalTime)));

    //更新歌词显示getTimeStr(pos)

    if (lrc->empty())
        return;
    int key = pos / 1000;
    QMap<int, QString>::iterator it;
    if (lrc->contains(key))
    {
        curLrc = lrc->value(key);
        it = lrc->find(key);
        if (it++ != lrc->end())
        {
            nextLrcStr = it.value();
        }
    }
    curLrc = curLrc.trimmed();
    curLrc.truncate(15);
    if (curLrc.length() > 15)
        curLrc += "...";

    nextLrcStr = nextLrcStr.trimmed();
    nextLrcStr.truncate(15);
    if(nextLrcStr.length() > 15)
        nextLrcStr += "...";

    currentLRC->setText("<center>" + curLrc +"</center>");
    nextLRC->setText("<center>" + nextLrcStr +"</center>");
    //cout << pos << curLrc;

}

//初始化歌词
void MusicPlayer::initLrc()
{
    if (lrc != 0)
        lrc->clear();
    if (list == 0)
        return;
    curLrc = "";
    nextLrcStr = "";
    //思路,用一个map存储10-》string的格式,然后时间到后载入,等待下一个时间
    if (list->isEmpty())
        return ;
    if (playerList == 0)
        return;
    QString fileNames = list->at(playerList->currentIndex());
    QString lrcNames = fileNames;
    int n = lrcNames.lastIndexOf('.');
    lrcNames.replace(n,lrcNames.length() - n,".lrc");
    QFile file(lrcNames);
    QString line;
    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QTextStream stream(&file);
        while(!stream.atEnd())
        {
            line = stream.readLine();
            int num = line.count('[');
            int last = line.lastIndexOf(']');
            QString str = line.right(line.length() - last -1);
            int begin = 0;
            while(num-- >0)
            {
                QString strs = line.mid(begin,10);
                begin += 10;
                strs.replace("[","");
                strs.replace("]","");
                int s = getSeconds(strs);
                if (s > 0)
                {
                    lrc->insert(s,str.trimmed());
                    //cout << s << "=" << lrc->value(s);
                }
            }
        }
    }
}

void MusicPlayer::setPosition(int pos)
{
    currentPos = pos;
}


void MusicPlayer::setPosition()
{
    player->setPosition(currentPos);
}

//play or pause
void MusicPlayer::playOrPause()
{
    QPixmap img(("images/play.png"));
    if (!isPlaying)
    {
        isPlaying = true;
        player->play();
        img.load("images/pause.png");
    }
    else
    {
        isPlaying = false;
        player->pause();
        img.load("images/play.png");
    }
    playOrPauseLabel->setPixmap(img.scaled(60,60));
}

//时间字符串00:00:00得到毫秒/秒,依赖操作系统
qint32 MusicPlayer::getSeconds(QString &timeStr)
{
    QStringList strs = timeStr.split(":");
    QString s;
    if (strs.size() > 0)
    {
        int m = strs.at(0).toDouble();
        int s = strs.at(1).toDouble();
        //cout << "m" << m;
        //cout << "s" << s;
        return m * 60 + s;
    }
    return 0;
}

//从时,分,秒获取总数秒
qint32 MusicPlayer::getSeconds(qint32 seconds_, qint32 minutes_, qint32 hours_)
{
    return seconds_ + minutes_ * 60 + hours_ * 3600;
}

//从duuation获取字符串
QString MusicPlayer::getTimeStr(qint32 seconds_)
{
    seconds_ /= 1000;
    qint32 minutes = seconds_ % 3600 / 60;
    qint32 seconds = seconds_ % 3600 % 60;
    minutes = minutes > 99 ? 99 : minutes + 100;
    seconds = seconds + 100;
    return QString::number(minutes).right(2).append(":").append(QString::number(seconds).right(2));
}

//改变时间提示
//void MusicPlayer::changeTime(qint64 time)
//{
//    timeLabel->setText(tr("T: <span style='color:Coral'>%1</span> / %2").arg(getTimeStr(time/1000)).arg(getTimeStr(totalTime)));
//}

//最小
void MusicPlayer::setMin()
{
    if (!this->isMinimized())
    {
        this->showMinimized();
    }
}

//改变音量提示
void MusicPlayer::changeVol(int vol)
{
    volLabel->setText(tr("V:%1%").arg(QString::number(vol)));
    player->setVolume(vol);
}

//窗体透明程度
void MusicPlayer::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.fillRect(this->rect(), QColor(100, 100, 100, 255));  //QColor最后一个参数80代表背景的透明度
}

//圆角窗体
void MusicPlayer::setRounded(bool b)
{
    if (!bmp)
    {
        delete bmp;
        bmp = 0L;
    }
    if (!p)
    {
        delete p;
        p = 0L;
    }
    bmp = new QBitmap(this->size());
    bmp->fill();             //fills the pixmap with white (default value) color
    p = new QPainter(bmp);
    p->setPen(Qt::NoPen);
    p->setBrush(Qt::black);
    if (b)
        p->drawRoundedRect(bmp->rect(),15,15);
    else
        p->drawRoundedRect(bmp->rect(),0,0);
    setMask(*bmp);//设置窗体遮罩
}

//移动窗体相关
void MusicPlayer::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        isMouseDown = true;
        oldLocation = event->globalPos() - this->pos();
    }
    event->ignore();
}
//移动窗体相关
void MusicPlayer::mouseMoveEvent(QMouseEvent *event)
{
    if (isMouseDown)
    {
        this->move(event->globalPos() - oldLocation);
        if (listUi != 0)
        {
            listUi->moves(this->sizeHint(), this->pos());
        }
    }
    event->ignore();
}
//移动窗体相关
void MusicPlayer::mouseReleaseEvent(QMouseEvent *event)
{
    isMouseDown = false;
    event->ignore();
}

(转载请注明作者和出处, 未经允许请勿用于商业用途)