QT音乐播放器

QT 专栏收录该内容
1 篇文章 0 订阅

QT功能十分强大,最重要的是跨平台移植性非常好,由于本人是学嵌入式的,所以做图形界面比较喜欢用QT,最近学习QT当做练习做了一个迷你版的音乐播放器,主要实现音乐播放、暂停、切换、音量大小调节,快进、添加和删除歌曲等基本功能,同时背景可以根据歌曲切换而切换,有歌词显示的功能,设计主界面主要如下:

整个QT项目下再放置三个文件夹,分别存放图片,歌词和歌曲文件。

images文件夹如下,有按钮图片,播放器的logo和歌曲的背景图片。

lrc文件夹如下,存放歌词文件,在网易云音乐和酷狗上获取歌词和歌曲的图片都很容易。

歌曲文件格式如下,当然这里将下载下来的歌词文件按照自己的格式改动了一下,大家可以按照自己的方式选择歌词的格式。

music文件夹如下,存放所有歌曲文件:

工程结构目录比较简单:

musicwidget.h代码如下:

#ifndef MUSICWIDGET_H
#define MUSICWIDGET_H

#include <QWidget>
#include <QListWidget>
#include <QMediaPlayer>
#include <QTime>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QFont>
#include <QTextStream>
#include <QString>
#include <QListWidgetItem>
#include <QColor>

#define MUSICLIST_MAXLEN 200
#define MUSICLRC_MAXLEN 500

namespace Ui {
class MusicWidget;
}

class MusicWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MusicWidget(QWidget *parent = 0);
    ~MusicWidget();

    void musicPositionChange(qint64 position);
    void setWindowBackgroundImage();

    void mousePressEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);

    void keyPressEvent(QKeyEvent *e);

private slots:


    void on_pb_addMusic_clicked();

    void on_lw_listMusic_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);

    void on_pb_test_clicked();

    void on_slider_volume_valueChanged(int value);

    void on_slider_musicTime_valueChanged(int value);

    void on_pb_startOrPause_clicked();

    void on_lw_listMusic_doubleClicked(const QModelIndex &index);

    void on_pb_lastMusic_clicked();

    void on_pb_nextMusic_clicked();

    void on_pb_voice_clicked();

    void on_pb_close_clicked();

    void on_pb_minWindow_clicked();

    void on_lw_listMusic_entered(const QModelIndex &index);

    void on_lw_listMusic_pressed(const QModelIndex &index);

    void on_lw_listMusic_itemEntered(QListWidgetItem *item);

    void on_pb_delMusic_clicked();

private:
    Ui::MusicWidget *ui;
    QString musicList[MUSICLIST_MAXLEN];
    QString musicLrc[MUSICLRC_MAXLEN];
    QString currentMusicName;
    int musicListCounter;
    int musicLrcLineCounter;
    int lrcAddLineCounter;
    int musicVolume_last;
    int musicVolume_now;
    QPoint startRelativePos;

    QMediaPlayer player;
    int playFlag;
    bool musicPositionChangeFlag;
    bool musicStartFlag;
    bool voiceOpenFlag;
};

#endif // MUSICWIDGET_H

musicwidget.c代码如下:

#include "musicwidget.h"
#include "ui_musicwidget.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QDebug>


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

    setFixedSize(this->width(), this->height());
    musicListCounter = 0;  //初始化音乐列表为空
    musicLrcLineCounter = 0;  //初始化歌词列表为空
    musicVolume_now = musicVolume_last = 30;  //音量为30
    playFlag = 0;
    musicPositionChangeFlag = false;
    musicStartFlag = false;
    voiceOpenFlag = true;  //初始时声音是开的

    player.setVolume(30);
    ui->slider_volume->setValue(30);

    ui->pb_startOrPause->setIcon(QIcon("images/bfzn_004.png" ));
    ui->pb_startOrPause->setFixedSize(40, 40);

    ui->pb_voice->setIcon(QIcon("images/voice_open.png" ));
    ui->pb_voice->setFixedSize(16, 16);

    ui->pb_test->hide();

    //ui->pb_close->setStyleSheet("color:red");  //设置按钮的字体颜色为红色

    connect(&player, &QMediaPlayer::positionChanged, this, &MusicWidget::musicPositionChange);

    setWindowFlags(Qt::FramelessWindowHint);//无边框
    //setAttribute(Qt::WA_TranslucentBackground);//背景透明

    //设置窗体背景
    //QPixmap pixmap = QPixmap("F:/QTProject/MusicBox/images/岑宁儿 - 追光者.png").scaled(this->size());
    QPixmap pixmap = QPixmap("images/start.png").scaled(this->size());
    QPalette  palette (this->palette());
    palette.setBrush(QPalette::Background, QBrush(pixmap));
    this-> setPalette( palette );

    //设置歌曲列表控件的透明度
    this->ui->lw_listMusic->setStyleSheet(QString("color:rgba(255,255,255,255);background-color:rgba(10,10,10,150)"));
    //设置歌词列表控件的透明度
    this->ui->lw_Lyric->setStyleSheet(QString("color:rgba(255,255,255,255);background-color:rgba(10,10,10,200)"));

}

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

//鼠标按下
void MusicWidget::mousePressEvent(QMouseEvent *e)
{
    if(e->buttons() == Qt::LeftButton)
        startRelativePos = e->pos();
}

//鼠标移动
void MusicWidget::mouseMoveEvent(QMouseEvent *e)
{
    if(startRelativePos.y() < 40 && startRelativePos.x() < 700)  //只有在窗口上部分才能拖动窗口
    if (e->buttons() & Qt::LeftButton)
        move(e->globalPos() - startRelativePos);
}

//鼠标松开
void MusicWidget::mouseReleaseEvent(QMouseEvent *e)
{
    e->accept();
}

void MusicWidget::musicPositionChange(qint64 position)
{


    qDebug() << "musicPositionChange" ;

        if(player.state() == QMediaPlayer::PlayingState)
        {
            playFlag++;
            if(playFlag >= 2)
            {
                qDebug() << "musicPositionChange->PlayingState" << QString::number(player.position()*100/player.duration());
                ui->slider_musicTime->setValue(player.position()*100/player.duration());
                musicPositionChangeFlag = true;  //表明是该函数修改触发的事件
                QTime duration(0, player.position() / 60000, qRound((player.position() % 60000) / 1000.0), 0);
                ui->lb_musicTime->setText(duration.toString(tr("mm:ss")));
                QTime duration2(0, player.duration() / 60000, qRound((player.duration() % 60000) / 1000.0), 0);
                ui->lb_musicTime->setText(ui->lb_musicTime->text() + "/" + duration2.toString(tr("mm:ss")));
                //如果歌曲播放完毕
                if(duration == duration2)
                {
                    qDebug() << "Music Success" << "Next music->" << musicList[(ui->lw_listMusic->currentIndex().row() + 1) % musicListCounter];
                    //当前歌曲播放完了,自动切换下一首歌曲
                    player.setMedia(QUrl::fromLocalFile(musicList[(ui->lw_listMusic->currentIndex().row() + 1) % musicListCounter]));
                    ui->lw_listMusic->setCurrentRow((ui->lw_listMusic->currentIndex().row() + 1) % musicListCounter);
                    player.play();
                    currentMusicName = ui->lw_listMusic->currentItem()->text();
                    setWindowBackgroundImage();

                }

                if(musicLrc[0].compare(currentMusicName) != 0)  //如果当前歌曲的歌词不在记录中,则重新载入相应的歌词
                {
                    QFile lrcFile("lrc/" + ui->lw_listMusic->currentItem()->text() + ".txt");
                    ui->lw_Lyric->clear();
                    if(lrcFile.open(QIODevice::ReadOnly))  //打开文件成功
                    {
                        QTextStream lrcFileStream(&lrcFile);

                        lrcFileStream.setCodec("UTF-8");
                        musicLrcLineCounter = 0;
                        musicLrc[musicLrcLineCounter++] = currentMusicName;
                        while (!lrcFileStream.atEnd())  //按行把所有歌词读入到数组中
                        {

                            QString line = lrcFile.readLine();
                            musicLrc[musicLrcLineCounter++] = line;
                        }
                        lrcFile.close();
                    }
                    else  //找不到该歌曲的歌词文件
                    {
                        int currentMusicRow=0;

                        ui->lw_Lyric->clear();
                        lrcAddLineCounter = 0;

                        for(int i=currentMusicRow-4; i<currentMusicRow+5; i++)
                        {
                            if(i == currentMusicRow)
                            {
                                ui->lw_Lyric->addItem("当前歌曲无歌词");
                            }
                            else
                            {
                                ui->lw_Lyric->addItem("");
                            }

                            lrcAddLineCounter++;

                            ui->lw_Lyric->setCurrentRow(lrcAddLineCounter-1);
                            ui->lw_Lyric->currentItem()->setTextAlignment(Qt::AlignCenter);

                            if(i == currentMusicRow)
                            {
                                QFont font;
                                font.setPointSize(18);

                                ui->lw_Lyric->setCurrentRow(4);
                                ui->lw_Lyric->currentItem()->setFont(font);
                                ui->lw_Lyric->currentItem()->setTextAlignment(Qt::AlignCenter);
                                ui->lw_Lyric->currentItem()->setTextColor(Qt::darkGreen);
                                //ui->lw_Lyric->currentItem()->setBackgroundColor(QColor(255,255,255,150));

                            }
                        }

                    }
                }
                else  //显示歌词
                {
                    int currentMusicRow=0;
                    for(currentMusicRow=0; currentMusicRow < musicLrcLineCounter; currentMusicRow++)  //在歌词数组中找到当前时间点的那一行歌词
                    {
                        QString mm,ss;
                        mm = musicLrc[currentMusicRow].mid(1, 2);
                        ss = musicLrc[currentMusicRow].mid(4, 2);
                        QTime duration3(0, mm.toInt(), ss.toInt(), 0);
                        if(duration3 == duration)  //如果找到与当前时间对应的歌词
                        {
                            break;
                        }
                    }
                    if(currentMusicRow < musicLrcLineCounter)  //如果找到了对应歌词
                    {
                        ui->lw_Lyric->clear();
                        lrcAddLineCounter = 0;

                        for(int i=currentMusicRow-4; i<currentMusicRow+5; i++)
                        {

                            if(i >= 0 && i < musicLrcLineCounter)
                            {
                                QStringList lrc = musicLrc[i].split("]");
                                if(lrc.count() == 2)
                                    ui->lw_Lyric->addItem(lrc.at(1));
                                else
                                    ui->lw_Lyric->addItem(musicLrc[i]);
                                //ui->lw_Lyric->addItem(musicLrc[i]);
                                lrcAddLineCounter++;

                                ui->lw_Lyric->setCurrentRow(lrcAddLineCounter-1);
                                ui->lw_Lyric->currentItem()->setTextAlignment(Qt::AlignCenter);

                            }
                            else
                            {
                                ui->lw_Lyric->addItem("");
                                lrcAddLineCounter++;

                                ui->lw_Lyric->setCurrentRow(lrcAddLineCounter-1);
                                ui->lw_Lyric->currentItem()->setTextAlignment(Qt::AlignCenter);

                            }
                            if(i == currentMusicRow)
                            {
                                QFont font;
                                font.setPointSize(18);

                                ui->lw_Lyric->setCurrentRow(4);
                                ui->lw_Lyric->currentItem()->setFont(font);
                                ui->lw_Lyric->currentItem()->setTextAlignment(Qt::AlignCenter);
                                ui->lw_Lyric->currentItem()->setTextColor(Qt::darkGreen);
                                //ui->lw_Lyric->currentItem()->setBackgroundColor(QColor(255,255,255,150));

                            }
                        }
                    }

                }
                ui->lw_Lyric->setCurrentRow(-1);  //取消歌词列表的选中状态
            }

        }
        else
        {
            playFlag = 0;
        }
}


void MusicWidget::on_pb_addMusic_clicked()
{
    bool hasSameItem = false;
    //QStringList path = QFileDialog::getOpenFileNames(this, "选择音乐文件", "E:\\CloudMusic");
    QStringList path = QFileDialog::getOpenFileNames(this, "选择音乐文件", "./music");
    for(int i=0; i<path.count(); i++)  //逐条添加歌曲到歌曲列表中
    {
        hasSameItem = false;
        for(int j=0; j<musicListCounter; j++)  //寻找是否有相同的地址的歌曲
        {
            if(musicList[j].compare(path.at(i)) == 0)
            {
                hasSameItem = true;
                break;
            }
        }
        if(hasSameItem == false)   //歌曲不重复则可以被添加进来
        {
            musicList[musicListCounter++] = path.at(i);  //把选取的每条信息加入记录列表
            QFileInfo info(path.at(i));
            ui->lw_listMusic->addItem(info.baseName());  //将路径转化为文件名
        }
    }
}

void MusicWidget::on_pb_delMusic_clicked()
{
    for(int i = ui->lw_listMusic->currentIndex().row(); i < musicListCounter-1; i++)
    {
        musicList[i] = musicList[i+1];
    }
    musicListCounter--;
    ui->lw_listMusic->takeItem(ui->lw_listMusic->currentIndex().row());
    qDebug() << "current:" << QString::number(ui->lw_listMusic->currentIndex().row());
}

void MusicWidget::on_lw_listMusic_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
    qDebug() << "current:" << current->text() << QString::number(ui->lw_listMusic->currentIndex().row());
}

void MusicWidget::setWindowBackgroundImage()
{
    //设置窗体背景
    QPixmap pixmap = QPixmap("images/" + ui->lw_listMusic->currentItem()->text() + ".png");   //加载背景图片
    if(pixmap.isNull() == false)  //能找到当前歌曲的背景图片
    {
        pixmap = pixmap.scaled(this->width(), this->height());  //调整图片大小拉伸自动适应窗口
        QPalette  palette (this->palette());
        palette.setBrush(QPalette::Background, QBrush(pixmap));
        this-> setPalette( palette );
    }
    else  //不能找到当前歌曲的背景图片,设置一个默认的背景图片
    {
        QPixmap pixmap = QPixmap("images/start.png");   //加载背景图片
        pixmap = pixmap.scaled(this->width(), this->height());  //调整图片大小拉伸自动适应窗口
        QPalette  palette (this->palette());
        palette.setBrush(QPalette::Background, QBrush(pixmap));
        this-> setPalette( palette );
    }
}

void MusicWidget::on_pb_test_clicked()
{
    /*
    ui->lb_musicTime->setText(QString::number( player.duration()));
    qDebug() << "duration:" << QString::number( player.duration()) << ", position:" << QString::number( player.position());

    ui->slider_musicTime->setValue(player.position()/player.duration());
    QTime duration(0, player.position() / 60000, qRound((player.position() % 60000) / 1000.0), 0);
    ui->lb_musicTime->setText(duration.toString(tr("mm:ss")));
    */

    QFont font;
    font.setPixelSize(25);
    ui->lw_listMusic->currentItem()->setFont(font);
    //ui->lw_listMusic->setStyleSheet("background-color:blue;");



    QFile lrcFile("lrc/岑宁儿 - 追光者.txt");
    if(!lrcFile.open(QIODevice::ReadOnly))  //打开文件失败
    {
        return;
    }
    QTextStream lrcFileStream(&lrcFile);
    lrcFileStream.setCodec("UTF-8");
    while (!lrcFileStream.atEnd())
    {
    QString line = lrcFile.readLine();
    line = line + "\n";

    }
    lrcFile.close();
}


void MusicWidget::on_slider_volume_valueChanged(int value)
{
    qDebug() << QString::number(ui->slider_volume->value()) << "," << QString::number(value);
    player.setVolume(value);
    if(musicVolume_now != value)
    {
        musicVolume_last = musicVolume_now;
        musicVolume_now = value;
    }

    if(value == 0)
    {
        if(voiceOpenFlag == true)
        {
            ui->pb_voice->setIcon(QIcon("images/voice_close.png" ));
        }
        voiceOpenFlag = false;
    }
    else
    {
        if(voiceOpenFlag == false)
        {
            ui->pb_voice->setIcon(QIcon("images/voice_open.png" ));
        }
        voiceOpenFlag = true;
    }
    ui->lb_volume->setText(QString::number(value) + "%");
}

void MusicWidget::on_slider_musicTime_valueChanged(int value)
{

    if(musicPositionChangeFlag == false)
    {
        if(musicStartFlag == true)
        {
            player.pause();
            player.setPosition(value*player.duration()/100);
            player.play();
            currentMusicName = ui->lw_listMusic->currentItem()->text();
        }
        else
        {
            player.setPosition(value*player.duration()/100);
        }
    }
    else
    {
        musicPositionChangeFlag = false;
    }
}

void MusicWidget::on_pb_startOrPause_clicked()
{
    if(!musicStartFlag)
    {
        ui->pb_startOrPause->setIcon(QIcon("images/bfzn_003.png" ));
        //ui->pb_startOrPause->setFixedSize(40, 40);
        musicStartFlag = true;
        //player.play();
        if(player.state() == QMediaPlayer::StoppedState)
        {
            player.setMedia(QUrl::fromLocalFile(musicList[ui->lw_listMusic->currentIndex().row()]));
            setWindowBackgroundImage();
        }
            //if(player.state() != QMediaPlayer::PlayingState)
            player.play();
            currentMusicName = ui->lw_listMusic->currentItem()->text();
    }
    else
    {
        ui->pb_startOrPause->setIcon(QIcon("images/bfzn_004.png" ));
        musicStartFlag = false;
        player.pause();
    }

}

void MusicWidget::on_lw_listMusic_doubleClicked(const QModelIndex &index)
{
    player.setMedia(QUrl::fromLocalFile(musicList[ui->lw_listMusic->currentIndex().row()]));
    player.play();
    currentMusicName = ui->lw_listMusic->currentItem()->text();
    musicStartFlag = true;
    ui->pb_startOrPause->setIcon(QIcon("images/bfzn_003.png" ));
    setWindowBackgroundImage();
}

void MusicWidget::on_pb_lastMusic_clicked()
{
    //切换上一首歌曲
    if(ui->lw_listMusic->currentIndex().row() - 1 >= 0)
    {
        player.setMedia(QUrl::fromLocalFile(musicList[(ui->lw_listMusic->currentIndex().row() - 1) % musicListCounter]));
        ui->lw_listMusic->setCurrentRow((ui->lw_listMusic->currentIndex().row() - 1) % musicListCounter);
    }
    else
    {
        player.setMedia(QUrl::fromLocalFile(musicList[musicListCounter - 1]));
        ui->lw_listMusic->setCurrentRow(musicListCounter - 1);
    }

    player.play();
    currentMusicName = ui->lw_listMusic->currentItem()->text();
    if(musicStartFlag == false)
    {
        musicStartFlag = true;
        ui->pb_startOrPause->setIcon(QIcon("images/bfzn_003.png" ));
    }
    setWindowBackgroundImage();

}

void MusicWidget::on_pb_nextMusic_clicked()
{
    //切换下一首歌曲
    player.setMedia(QUrl::fromLocalFile(musicList[(ui->lw_listMusic->currentIndex().row() + 1) % musicListCounter]));
    ui->lw_listMusic->setCurrentRow((ui->lw_listMusic->currentIndex().row() + 1) % musicListCounter);

    player.play();
    currentMusicName = ui->lw_listMusic->currentItem()->text();
    if(musicStartFlag == false)
    {
        musicStartFlag = true;
        ui->pb_startOrPause->setIcon(QIcon("images/bfzn_003.png" ));
    }
    setWindowBackgroundImage();
}

void MusicWidget::on_pb_voice_clicked()
{

    if(voiceOpenFlag == false)
    {
        ui->pb_voice->setIcon(QIcon("images/voice_open.png" ));
        ui->slider_volume->setValue(musicVolume_last);
        voiceOpenFlag = true;
    }
    else
    {
        ui->slider_volume->setValue(0);
        //on_slider_volume_valueChanged(0);
        ui->pb_voice->setIcon(QIcon("images/voice_close.png" ));
        voiceOpenFlag = false;
    }
}

void MusicWidget::on_pb_close_clicked()
{
    this->close();  //关闭窗体
}

void MusicWidget::on_pb_minWindow_clicked()
{
    this->showMinimized();  //最小化窗体
}

void MusicWidget::keyPressEvent(QKeyEvent *e)
{
    qDebug() << "keyPressEvent" << QString::number(e->key());
    if(e->key()==Qt::Key_Enter || e->key()==Qt::Key_Return)  //如果在音乐列表按下回车键
    {
        qDebug() << "Key_Enter";
        if(ui->lw_listMusic->hasFocus())  //如果当前焦点在音乐列表上
        {
            player.setMedia(QUrl::fromLocalFile(musicList[ui->lw_listMusic->currentIndex().row()]));
            setWindowBackgroundImage();
            player.play();
            currentMusicName = ui->lw_listMusic->currentItem()->text();
            musicStartFlag = true;
        }
    }
}

void MusicWidget::on_lw_listMusic_entered(const QModelIndex &index)
{
    qDebug() << "enter";
}

void MusicWidget::on_lw_listMusic_pressed(const QModelIndex &index)
{
    qDebug() << "press";
}

void MusicWidget::on_lw_listMusic_itemEntered(QListWidgetItem *item)
{
    qDebug() << "itemEntered";
}


总体运行结果如下:

代码下载链接:https://download.csdn.net/download/qq_34254642/10917513

 

 2019年12月19日:

最近有一些朋友给我发消息说不能播放音乐或者是工程编译报错,我也经常逛CSDN查找资料,明白那种充满期待下载了别人的资源然后又用不了的心情,真的是一种非常糟糕的体验,针对以上问题的解决办法。

(1)工程不能编译:工程是QT5.6版本的,因为工程保留的编译配置是我本人电脑的配置,大家需要根据自己的实际情况改下配置。

(2)工程编译成功,界面也出来了,但是播放不了音乐或者报错提示如下:

DirectShowPlayerService::doRender: Unresolved error code 80040266 

原因是Qt 中的多媒体播放,底层是使用DirectShowPlayerService,所以安装一个DirectShow解码器,例如LAV Filters,就可以解决运行出错问题,这里我帮大家找到了下载地址http://files.1f0.de/lavf/LAVFilters-0.65.exe,下载安装就OK了,参考了下面这位朋友的博客https://blog.csdn.net/mmmmmmyy/article/details/81877233在此表示感谢。

(3)因为之前写这个播放器的时候刚学QT,代码水平也不是很高,所以会有一些BUG,有兴趣的大家可以继续改进,就当做一个参考就行了。

(4)知道大家在CSDN上下载资源要花C币,要么就是到某宝上代下,我下载资源的时候也想过如果作者给百度云或者gittub的链接该多好啊,所以,己所不欲勿施于人。上传个百度云的链接链接:https://pan.baidu.com/s/1R_7ZJX73Y4lHnxBzxNlqLg 
提取码:7ncx 
 

 

评论 15 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

心城追梦

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值