QT平台上制作的音乐播放器

花了两个礼拜的时间在qt平台上做了一个中等的音乐播放器,以下是一些.cpp和.h文件仅供参考,这个播放器还有一些功能需要完善,比如说显示歌词,上网搜索歌曲等等。在整个播放器的制作过程当中,首先需要了解一下一个音乐播放器需要用到哪些模块,比如说资源管理器,音乐信息对象,物理连接设备等等,分清楚这些模块它们各自的功能,然后再开始做,这样要稍微容易一些。有一个问题需要注意一下,虽然说这是一个小小的问题,但也花了我几天的时间,问题就是在新建的pro里面没有加phonon,因为音乐播放器在播放歌曲的时候需要phonon对歌曲进行解析,才可以播放,所以值得注意。

 

主窗口加列表截图如下:

 

如下是widget.cpp文件

#include "widget.h"

#include "ui_widget.h"

#include "musiclist.h"

#include <QTime>

#include <QUrl>

#include <QtGlobal>

#include <QtGui>

int num = 0;

Widget::Widget(QWidget *parent) :

   QWidget(parent),

    ui(new Ui::Widget)

{

   ui->setupUi(this);   // 建立主窗口

   // 一个音乐文件列表建立

   list= new musiclist(this);

   QString str = tr("播放列表"); // 设置窗口的名称

   list->setWindowTitle(str);   // 如果是这条代码(list->setWindowTitle("音乐播放器")),则会显示乱码

   list->setFixedSize(285, 300);  // 设置窗口的长和宽

   list->installEventFilter(this);  // object 事件过滤器,比如说是鼠标点击,移动等等

   list->ui->tableWidget->installEventFilter(this);

   list->ui->tableWidget->setColumnWidth(1, 100);  // 调节第1列的宽度

   list->ui->tableWidget->setColumnHidden(0, 100);  // 调节第0列的宽度

   readSettings();  // 读取主窗口和列表宽的位置

   // 主窗口模块

   QString str2 = tr("音乐播放器 (陈伟东制作)");

   this->setWindowTitle(str2);

   this->setFixedSize(280, 150);

   this->ui->listWidget->setStyleSheet("background-image:url(images/3.jpg)");    // 添加背景图片,具体参考QT收藏资料,也可以使用另外一种方法

   // 建立媒体管理

   musicInformationMediaObject = new Phonon::MediaObject(this);  // 音乐信息对象

   mediaObject = new Phonon::MediaObject(this);   // 分配一个资源管理器

   audioOutput = new Phonon::AudioOutput(); // 有些时候是 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory),它的作用是将源文件映射到物理设备

   Phonon::createPath(mediaObject, audioOutput); // 用creatPath函数将资源管理器和audioOutput连接起来

   creation();  // 初始化歌曲器件,以及托盘menu的一些菜单

   // 声音控制模块

   volumeSlider = new Phonon::VolumeSlider(this);   // 在主窗口里申请一个volumSlider

   volumeSlider->setAudioOutput(audioOutput);  // 使得音量控制器和音乐文件连接起来

   volumeSlider->move(175, 130);

   volumeSlider->resize(20, 20);

   volumeSlider->setFixedWidth(90); //固定音量条宽度的大小

   // 进度条控制及设置模块

   seekSlider = new Phonon::SeekSlider(this);  // 在主窗口中分配seekSlider  函数中的this必需得加上去,因为this代表主窗口的意思

   seekSlider->setMediaObject(mediaObject);  // 使得进度条和歌曲进度一致

   seekSlider->move(2, 2);     // 设置进度条在主窗口的哪个位置  做上角为(0,0)

seekSlider->resize(265, 20);   // 设置进度条宽度

 

   // 媒体状态发生变化时,有如下信号与槽的关系

connect(mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(mediaObjectStateChanged(Phonon::State,Phonon::State)));

 

   // 双击音乐音乐列表里面的音乐时使得点到的歌曲播放

connect(list->ui->tableWidget, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(tableWidget_cellDoubleClicked(int,int)));

 

   // 音乐列表和主窗口里(列表)按钮的连接

connect(list, SIGNAL(listClose()), this->ui->toolButton, SLOT(toggle()));

 

   // 在当前的歌曲快要播放完时

   connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(musicAboutToFinish()));

connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)), this, SLOT(currentMusicSourceChanged(Phonon::MediaSource)));

 

   // 当musicInformationMediaObject信息对象发生变化时,建立如下槽和信号的连接

connect(musicInformationMediaObject,SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(musicInformationStateChanged(Phonon::State,Phonon::State)));

 

   // 音乐文件的时间显示与显示建立信号与槽的联系

   connect(mediaObject,SIGNAL(tick(qint64)),this,SLOT(showTime(qint64)));

   connect(this,SIGNAL(mySignal()),this,SLOT(close()),Qt::QueuedConnection);

}

Widget::~Widget()

{

   delete ui;

}

void Widget::tableWidget_cellDoubleClicked(int row, int column)   // 双击一首歌曲

{

   mediaObject->stop();

   mediaObject->clearQueue();  // clear the quenue of the media object

   if (row > sourceList.size())

   {

       return;

   }

   mediaObject->setCurrentSource(sourceList.at(row));   // 设置mediaobject当前的歌曲

   mediaObject->play();

}

void Widget::currentMusicSourceChanged(Phonon::MediaSource source) // 当自动播放下一曲音乐时,在tableWidget中让它为选中状态

{

   list->ui->tableWidget->selectRow(sourceList.indexOf(source));

   mediaObject->pause(); // 在此改变一下状态触发mediaObjectStateChanged槽函数

}

// 音乐信息变化时,比如说增加一些歌曲,或者是清空列表等等

void Widget::musicInformationStateChanged(Phonon::State newState,Phonon::State)

{

   if (newState != Phonon::StoppedState && newState != Phonon::PausedState)

       return ;

   if (musicInformationMediaObject->currentSource().type() == Phonon::MediaSource::Invalid)

       return ;

   /*

   刚开始,媒体对象会进入Phonon::LoadingState状态,此时后端进行资源的载入。

   当Phonon::LoadingState完成后就会进入Phonon::StoppedState 状态,

   这时才能添加新的资源。

   */

   QMap<QString, QString> metaData = musicInformationMediaObject->metaData();

   int rowNum = list->ui->tableWidget->rowCount();

   list->ui->tableWidget->insertRow(rowNum);  // 插入一行空行

   QString title = metaData.value("TITL");  // 歌曲名称

   if (title == "")

   {

       QString fileName = musicInformationMediaObject->currentSource().fileName();

       QString mp3Name = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1);

       title= mp3Name;      // 花括号里面的语句作用是求出音乐文件的name

   }

    QTableWidgetItem *titleItem = new QTableWidgetItem(title);

    list->ui->tableWidget->setItem(rowNum,0,titleItem);

    QTableWidgetItem *artistItem = new QTableWidgetItem(metaData.value("ARTIST"));

    // 歌手名称

    list->ui->tableWidget->setItem(rowNum,1,artistItem);

    // 让列表显示时间还没有解决

    qint64tTime = mediaObject->totalTime();

    QTime tolTime(0,(tTime / 60000) % 60,(tTime / 1000) % 60);

    QString time = tolTime.toString("mm:ss");

    QTableWidgetItem *totalTime = new QTableWidgetItem(time); //专辑

    list->ui->tableWidget->setItem(rowNum,2,totalTime);

    list->ui->tableWidget->close();

    list->ui->tableWidget->show(); // 列表信息发生变化,先关掉,然后再显示

   if (list->ui->tableWidget->selectedItems().isEmpty())

    { //如果没有选择行

        list->ui->tableWidget->selectRow(0);   //选择第一行

        mediaObject->setCurrentSource(musicInformationMediaObject->currentSource());

    }

    int index = sourceList.indexOf(musicInformationMediaObject->currentSource()) + 1;

    if (sourceList.size() > index)

    {

        musicInformationMediaObject->setCurrentSource(sourceList.at(index));

    }

}

void Widget::mediaObjectStateChanged(Phonon::State, Phonon::State)

{

   switch(mediaObject->state())

   {

   case Phonon::PlayingState:

       {

            QString fileName = mediaObject->currentSource().fileName();

            QString title = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1);

            this->ui->label->setText(title);

            trayicon->setToolTip(title);

            break;

       }

   case Phonon::StoppedState:

            trayicon->setToolTip("停止" );

            break;

   case Phonon::PausedState:

            trayicon->setToolTip("暂停");

            break;

    case Phonon::LoadingState:

            trayicon->setToolTip("加载");

            break;

   case Phonon::ErrorState:

            trayicon->setToolTip("错误" );

            break;

   case Phonon::BufferingState:

            trayicon->setToolTip("缓冲");

           break;

   default:

       break;

   }

}

void Widget::creation()

{

 /*   QIcon iconremove("images/remove.png");   // 为按键分配图标

   remove = new QAction(iconremove,tr("清空播放列表"),this);

   QIcon iconsound("images/sound.png");

   QIcon iconstop("images/gtk-media-stop.png");

   QIcon iconopen("images/gtk-open.png");

   QIcon iconexit("images/exit.png"); */

   remove= new QAction(tr("清空"),this);

   connect(remove,SIGNAL(triggered()),this,SLOT(removelist()));

   sound= new QAction( tr("静音"), this);

   sound->setCheckable(true);

   connect(sound,SIGNAL(triggered(bool)),audioOutput ,SLOT(setMuted(bool)));

   stop= new QAction(tr("停止"),this);

   connect(stop,SIGNAL(triggered()), this, SLOT(stopSlot()));

   open= new QAction( tr("打开"),this);

    connect(open, SIGNAL(triggered()), this, SLOT(on_openFileBtn_clicked()));

   exit= new QAction(tr("退出"),this);

   connect(exit,SIGNAL(triggered()),this,SLOT(exitSlot()));

   QIcon ico("images/VMP2.png");

   trayicon = new QSystemTrayIcon(this);

   trayicon->setIcon(ico);

   trayicon->setToolTip(tr("正在载入"));

   menu= new QMenu(this);

   menu->addAction(remove);

   menu->addAction(open);

   menu->addAction(sound);

    menu->addSeparator();

   menu->addAction(stop);

   menu->addAction(exit);

    trayicon->setContextMenu(menu);

   trayicon->show();

   trayicon->showMessage(tr("音乐播放器"),tr("欢迎你使用本软件"),QSystemTrayIcon::Information,10000);

   connect(trayicon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),

            this,SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));//图标被激活时

}

void Widget::exitSlot()

{

   this->hide();

   this->close();

}

void Widget::stopSlot()

{

   mediaObject->stop();

}

void Widget::removelist()

{

   mediaObject->stop();

   int row = list->ui->tableWidget->rowCount();

   for (int i = 0; i < row; i++)

       list->ui->tableWidget->removeRow(0);

   list->ui->tableWidget->close();

   list->ui->tableWidget->show();

   mediaObject->clear();

   sourceList.clear();

}

void Widget::iconActivated(QSystemTrayIcon::ActivationReason reason)

{

   switch(reason)

   {

   case QSystemTrayIcon::Trigger://单击

        this->setWindowState(Qt::WindowActive);//恢复窗口显示

        this->show();

        break;

   case QSystemTrayIcon::DoubleClick://双击

        this->hide();

        list->hide();

        break;

   case QSystemTrayIcon::MiddleClick:

       trayicon->showMessage(tr("音乐播放器"),tr("欢迎使用本软件"),QSystemTrayIcon::Information,10000);

       break;

   default:

       ;

   }

}

void Widget::on_openFileBtn_clicked()

{

   QStringList files = QFileDialog::getOpenFileNames(this, tr("Selec Files to play"), QDesktopServices::storageLocation(QDesktopServices::MusicLocation));    // 从系统当中添加音乐文件

   QString file;

   int index = sourceList.size();  // 计算音乐列表当中有多少个文件

   foreach(file, files)      // 添加音乐file

   {

       Phonon::MediaSource source(file);

       sourceList.append(source);    // 使得添加进来的file按循序排列

   }

   if (!sourceList.isEmpty())  // 将音乐信息对象的当前文件指定为还没有加文件前的位置

       musicInformationMediaObject->setCurrentSource(sourceList.at(index));

}

void Widget::readSettings() // 读取主窗口的位置信息

{

   QSettings settings("ecjtu", "Phonon Example");

   QPoint pos = settings.value("pos", QPoint(400, 200)).toPoint();

   move(pos);

   //QSize size = settings.value("size", QSize(298,412)).toSize();

   //resize(size);

}

void Widget::writeSettings() // 记录主窗口的位置信息

{

   QSettings settings("ecjtu","Phonon Example");

   settings.setValue("pos", pos());

   //settings.setValue("size", size());

}

void Widget::on_playOrpause_clicked() // 音乐文件在音乐列表当中的排列是:0 1 2 3 4 5 6

{

   if(sourceList.isEmpty())   // 判断音乐列表是否为空

   {

       QMessageBox::information(this, tr("警告"), tr("no files to play"));   // 当没有音乐时, 显示警告信息

       return ;

   }

   if (mediaObject->state() == Phonon::PlayingState)  // 如果按下暂停按钮

       mediaObject->pause();   // 暂停播放歌曲

   else

       mediaObject->play();;   // 按音乐列表播放歌曲

}

void Widget::on_previousMusic_clicked()

{

   int index = sourceList.indexOf(mediaObject->currentSource())-1;   //  找到当前歌曲的序列号

   if (index >= 0)

   {

       mediaObject->stop();

       mediaObject->setCurrentSource(sourceList.at(index));   // 设置当前播放歌曲下一首的序列号

       mediaObject->play();

   }

   else

       QMessageBox::information(this, tr("警告"), tr("没有上一首歌曲"));

}

void Widget::on_nextMusic_clicked()

{

   int index = sourceList.indexOf(mediaObject->currentSource()) + 1;//  获取当前播放类表歌曲的位置然后加一表示下一首的歌曲

   if (index < sourceList.size())    // 利用sourceList.size()来得到列表当中的音乐文件个数

   {

       mediaObject->stop();

       mediaObject->setCurrentSource(sourceList.at(index));   // 播放指定index的歌曲

       mediaObject->play();

   }

   else

       QMessageBox::information(this, tr("警告"), tr("没有下一首歌曲"));

}

void Widget::musicAboutToFinish() // 本首音乐快结束时

{

   int index = sourceList.indexOf(mediaObject->currentSource()) + 1;

   mediaObject->setCurrentSource(sourceList.at(index)); // 注意:不会产生状态的改变state

   mediaObject->play();

}

void Widget::showTime(qint64 time)    // 显示歌曲的时间进度

{

   qint64temp = mediaObject->totalTime();

   QTime totalTime(0,(temp / 60000) % 60,(temp / 1000) % 60,time %1000);

   QTime curTime(0,(time / 60000) % 60,(time / 1000) % 60,time %1000);

       ui->showTime->setText(tr("%1 / %2")

                       .arg(curTime.toString("mm:ss"))

                       .arg(totalTime.toString("mm:ss")));

   ui->showTime->update();

}

void Widget::on_toolButton_clicked(bool checked)

{

   num++;

   if (num % 2 == 1)

   {

       list->listReadSettings();

       list->show();

   }

   else

   {

      list->listWriteSettings();

       list->hide();

   }

}

void Widget::changeEvent(QEvent *e)

{

   QWidget::changeEvent(e);

   switch (e->type()) {

   case QEvent::LanguageChange:

       ui->retranslateUi(this);

       break;

   default:

       break;

   }

}

void Widget::closeEvent(QCloseEvent *e)

{

   writeSettings();

   list->listWriteSettings();

   if (this->isVisible())

    {

       this->hide();

       list->hide();

       trayicon->showMessage(tr("MusicPlay"), tr("最小化"),QSystemTrayIcon::Information,15000);

       e->ignore();

   }

}

bool Widget::eventFilter(QObject *object, QEvent *event)

{

   qDebug() << object;

    if(object == list->ui->tableWidget) // 过滤表格的事件

   {

       qDebug() << "event" << event;

       if(event->type() == QEvent::ContextMenu)

       {

            QContextMenuEvent *contextevent = static_cast<QContextMenuEvent *>(event);

            QMenu menu(this);

            menu.addAction(remove);

            menu.exec(contextevent->globalPos());

            return true;

       }

       else if(event->type() == QEvent::DragEnter)

       {

            QDragEnterEvent *dragEnterevent = static_cast<QDragEnterEvent *>(event);

            if(dragEnterevent->mimeData()->hasFormat("text/uri-list"))

                    dragEnterevent->acceptProposedAction();

            return true;

       }

       else if(event->type() == QEvent::Drop)

       {

           QDropEvent *dropevent = static_cast<QDropEvent *>(event);

            dropEvent(dropevent);

            return true;

       }

       else return false;

   }

   return QWidget::eventFilter(object,event);

}

void Widget::dragEnterEvent(QDragEnterEvent *e)

{

   if(e->mimeData()->hasFormat("text/uri-list"))

            e->acceptProposedAction();

}

void Widget::dropEvent(QDropEvent *e)

{

   QList<QUrl> urls= e->mimeData()->urls();

   QString fileName = urls.first().toLocalFile();

   int index = sourceList.size();  //获取当前列表的长度

   for(int i=0; i<urls.length(); i++)

   {

       QString string = urls.at(i).toString();

       Phonon::MediaSource source(string);

       sourceList.append(source);//在当前列表后加入一条记录

   }

   if(!sourceList.isEmpty())

      musicInformationMediaObject->setCurrentSource(Phonon::MediaSource(sourceList.at(index)));

}

void Widget::moveEvent(QMoveEvent *e)

{

   if(isTouched)

   {

       QPoint p = e->pos() - e->oldPos();

       list->move(list->pos() + p);

   }

   else

   {

       isTouched = false;

       if(qAbs(list->y()- this->y() - this->frameGeometry().height()) < 20)

       {

            isTouched = true;

            this->move(this->x(),list->y()+this->frameGeometry().height());

       }

       if(qAbs(this->x() - list->x() - list->frameGeometry().width()) < 20)

       {

            isTouched = true;

            this->move(list->x()+list->frameGeometry().width(),this->y());

       }

       if(qAbs(this->x() + this->frameGeometry().width() - list->x()) < 20)

        {

            isTouched = true;

            this->move(list->x()-this->frameGeometry().width(),this->y());

       }

   }

   QWidget::moveEvent(e);

}

 

如下是musiclist.h

#ifndef MUSICLIST_H
#define MUSICLIST_H
#include <QWidget>
namespace Ui {
    class musiclist;
}
class musiclist : public QWidget
{
    Q_OBJECT
public:
    explicit musiclist(QWidget *parent = 0);
    ~musiclist();
    Ui::musiclist *ui;
    void listReadSettings();
    void listWriteSettings();
protected:
    void changeEvent(QEvent *e);
    void moveEvent(QMoveEvent *);
signals:
    void listClose();
};
#endif // MUSICLIST_H
 
如下是widget.h文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <phonon>
#include "musiclist.h"
#include "ui_musiclist.h"
#include <QTimer>
#include <QSystemTrayIcon>
namespace Ui {
    class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    void creation();
protected:
   void changeEvent(QEvent *e);
   void closeEvent(QCloseEvent *e);
   void dragEnterEvent(QDragEnterEvent *);
   bool eventFilter(QObject *, QEvent *);
   void dropEvent(QDropEvent *);
   void moveEvent(QMoveEvent *);
private:
    Ui::Widget *ui;
    musiclist *list;
    Phonon::MediaObject *mediaObject;
    Phonon::MediaObject *musicInformationMediaObject;
    Phonon::AudioOutput *audioOutput;
    Phonon::SeekSlider *seekSlider;
    Phonon::VolumeSlider *volumeSlider;
    QList<Phonon::MediaSource> sourceList;//播放列表
    void readSettings();
    void writeSettings();
    QAction *remove;
    QAction *open;
    QAction *exit;
    QAction *sound;
    QAction *stop;
    QMenu *menu;
    QSystemTrayIcon *trayicon;
    bool isTouched;
private slots:
    void removelist();
    void tableWidget_cellDoubleClicked(int row, int column);
    void musicInformationStateChanged(Phonon::State newState,Phonon::State);
    void on_toolButton_clicked(bool checked);
    void on_nextMusic_clicked();
    void on_previousMusic_clicked();
    void on_playOrpause_clicked();
    void on_openFileBtn_clicked();
    void showTime(qint64);
    void musicAboutToFinish();
    void currentMusicSourceChanged(Phonon::MediaSource source);
    void iconActivated(QSystemTrayIcon::ActivationReason reason);
    void mediaObjectStateChanged(Phonon::State, Phonon::State);
    void exitSlot();
    void stopSlot();
signals:
    void mySignal();
};
#endif // WIDGET_H
 
如下是musiclist.cpp文件
#include "musiclist.h"
#include "ui_musiclist.h"
#include <QSettings>
musiclist::musiclist(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::musiclist)
{
    ui->setupUi(this);
    listReadSettings();
    ui->tableWidget->setAcceptDrops(true);
    this->setWindowFlags(Qt::Tool);
}
musiclist::~musiclist()
{
    delete ui;
}
void musiclist::listReadSettings()  // 读取application位置及大小信息
{
    QSettings settings("ecjtu", "Phonon LIST");
    QPoint pos =  settings.value("pos", QPoint(this->x(), this->y())).toPoint();
    QSize size = settings.value("size", QSize(300, 320)).toSize();
    move(pos);
    resize(size);
}
void musiclist::listWriteSettings()  // 记录application的位置及大小信息
{
    QSettings settings("ecjtu", "Phonon LIST");
    settings.setValue("pos", pos());
    settings.setValue("size", size());
}
void musiclist::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
void musiclist::moveEvent(QMoveEvent *e)
{
    if(qAbs((this->y()- this->parentWidget()->y() - this->parentWidget()->frameGeometry().height())) < 20)
    {
        this->move(this->x(),this->parentWidget()->y() + this->parentWidget()->frameGeometry().height());
    }
    if(qAbs(this->x()+this->frameGeometry().width() - this->parentWidget()->x()) < 20)
    {
        this->move(this->parentWidget()->x()-this->frameGeometry().width(),this->y());
    }
    if(qAbs(this->x()-this->parentWidget()->frameGeometry().width()-this->parentWidget()->x()) < 20)
    {
        this->move(this->parentWidget()->x()+this->parentWidget()->frameGeometry().width(),this->y());
    }
    QWidget::moveEvent(e);
}
 
如下是main.cpp文件
#include <QtGui/QApplication>
#include <QTextCodec>
#include "widget.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
    Widget w;
    w.show();
    return a.exec();
}
 

 

发布了12 篇原创文章 · 获赞 11 · 访问量 6万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览