QT5:C++實現基於multimedia的音樂播放器(一)

来源:https://www.cnblogs.com/guolao/archive/2018/04/23/8922552.html
-Advertisement-
Play Games

上一篇里簡略的描述了一下播放器的實現,這一篇開始具體描述一下過程。 環境配置:Qt Creator 打開Qt Creator,創建一個new project,項目名稱隨你喜歡(我的是MusicPlayer),類名也隨你喜歡(我的是Music),基類選擇QWidget,不勾選界面UI(你也可以勾選UI ...


上一篇里簡略的描述了一下播放器的實現,這一篇開始具體描述一下過程。

環境配置:Qt Creator

打開Qt Creator,創建一個new project,項目名稱隨你喜歡(我的是MusicPlayer),類名也隨你喜歡(我的是Music),基類選擇QWidget,不勾選界面UI(你也可以勾選UI,用QT自帶的UI設計來創建界面),然後要記住項目保存路徑不能有中文

創建成功後,在MusicPlayer.pro(項目名稱.pro)裡加上“QT += multimedia”這一句:

1 QT += core gui
2 QT += multimedia
3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

然後在頭文件music.h(類名.h)里添加要用到的頭文件名:

 1 #include <QWidget>
 2 #include <QMediaPlayer>
 3 #include <QPushButton>
 4 #include <QSlider>
 5 #include <QLabel>
 6 #include <QTime>
 7 #include <QPaintEvent>
 8 #include <QMediaPlaylist>
 9 #include <QTimer>
10 #include <QListWidget>

並且在music類里寫上要用到的對象成員和函數:

 1 class Music : public QWidget
 2 {
 3     Q_OBJECT
 4 public:
 5     explicit Music(QWidget *parent = 0);
 6     static int z;
 7 
 8 public slots:
 9     void addMoremusic();
10     void playMusic();
11     void preMusic();
12     void nextMusic();
13     void meteOpen();
14     void volumChange(int);
15     void positionChange(qint64 position);
16     void showMessage(bool);
17     void seekChange(int position);
18     void posChange();
19     void clearMessage();
20     void musicPlayPattern();
21 
22 private:
23     void init_controls();
24     void init_skin();
25 
26     QPushButton *BtnClose;
27     QPushButton *BtnMin;
28     QPushButton *BtnPlay;
29     QPushButton *BtnPrev;
30     QPushButton *BtnNext;
31     QPushButton *muteButton;
32     QPushButton *addMore;
33     QPushButton *playPattern;
34     QSlider     *volumeControl;
35     QSlider     *seekSlider;
36     QLabel      *showTime;
37     QLabel      *showPro;
38     QLabel      *showMge;
39     QLabel      *title;
40     QLabel      *message;
41     QListWidget *list;
42     bool        add;
43     QTimer      *timer;
44     QTimer      *timer2;
45     int         moved;
46     QPoint      dragPosition;
47     QMediaPlayer   *player;
48     QMediaPlaylist * playList;
49 
50 protected:
51     void paintEvent(QPaintEvent *event);
52     void mousePressEvent(QMouseEvent *event);
53     void mouseMoveEvent(QMouseEvent *event);
54 };
View Code

還要在源文件music.cpp裡加上要用的頭文件名:

 1 #include "music.h"
 2 #include <QPixmap>
 3 #include <QFile>
 4 #include <QPainter>
 5 #include <QFileDialog>
 6 #include <QUrl>
 7 #include <QDebug>
 8 #include <QMediaMetaData>
 9 #include <QMessageBox>
10 #include <QFileInfo>

接著添加資源文件,把要用的圖標和背景圖片都添加到項目里,然後就可以在music.cpp里寫播放器的界面了。

 1 Music::Music(QWidget *parent) : QWidget(parent)
 2 {
 3     QPixmap background;
 4     background.load(":/image/music_bg.bmp");//載入背景圖片
 5     this -> resize(background.width(),background.height());//設置視窗和背景圖片大小一致
 6     this -> setWindowFlags(Qt::FramelessWindowHint);//產生一個無視窗邊框的視窗,用戶無法改變它的大小也無法移動它
 7     add = false;
 8     moved = 0;
 9     timer = new QTimer(this);
10     timer2 = new QTimer(this);
11 
12     player = new QMediaPlayer(this);//QMediaplayer用於解析音頻文件和視頻文件
13     playList = new QMediaPlaylist;
14     
15     init_controls();//創建按鈕
16     init_skin();//外部載入qss文件,繪製界面樣式
17 
18     connect(player, SIGNAL(metaDataAvailableChanged(bool)), this, SLOT(showMessage(bool)));
19     connect(seekSlider,SIGNAL(sliderMoved(int)), this,SLOT(seekChange(int)));
20 }

因為我創建的是一個無法移動的窗體,所以重寫滑鼠左鍵函數來讓它可以被移動,這樣的話,滑鼠左鍵按住時可以拖動窗體了:

//令視窗可以被拖動
void Music::mousePressEvent(QMouseEvent *event){
    if(event->buttons()==Qt::LeftButton)
    {
        dragPosition=event->globalPos()-frameGeometry().topLeft();
        event->accept();
    }
}

void Music::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton)//event->buttons()==Qt::LeftButton && event ->y() < 50 && event ->x() < 330
    {
        this ->move(event->globalPos() - dragPosition);
        event->accept();
    }
}
//繪製背景
void Music::paintEvent(QPaintEvent *event)
{
    QPainter paint(this);
    QPixmap backgound;
    backgound.load(":/image/music_bg.bmp");
    paint.drawPixmap(0, 0, backgound.width(), backgound.height(),backgound);
    event ->accept();

}

然後寫創建按鈕的函數以及連接槽函數來響應信號的連接語句:

//創建按鈕
void Music::init_controls()
{   
    BtnClose = new QPushButton(this);
    BtnClose -> setObjectName("BtnClose");//如果要對這個對象單獨設stylesheet的話一定要設置它的objectName
    BtnClose -> setGeometry(365,2,30,30);//視窗左上角為原點(X365,Y2),(寬30,高30)
    BtnClose -> setToolTip(tr("退出"));
    BtnClose -> setCursor(QCursor(Qt::PointingHandCursor));//滑鼠指針形狀為手

    BtnMin=new QPushButton(this);
    BtnMin->setObjectName(tr("BtnMin"));
    BtnMin->setGeometry(330,5,25,30);
    BtnMin->setToolTip(tr("最小化"));
    BtnMin->setCursor(QCursor(Qt::PointingHandCursor));

    playPattern=new QPushButton(this);
    /*QIcon icon1(":/image/Seq.png");
    playPattern->setIcon(icon1);*/
    playPattern->setObjectName(tr("playPattern"));
    playPattern->setGeometry(20,255,50,50);
    playPattern->setToolTip(tr("列表迴圈"));
    playPattern->setCursor(QCursor(Qt::PointingHandCursor));


    BtnPlay=new QPushButton(this);
    BtnPlay->setObjectName(tr("BtnPlay"));
    BtnPlay->setGeometry(160,250,56,56);
    BtnPlay->setToolTip(tr("播放"));
    BtnPlay->setCursor(QCursor(Qt::PointingHandCursor));

    BtnPrev=new QPushButton(this);
    BtnPrev->setObjectName(tr("BtnPrev"));
    BtnPrev->setGeometry(120,255,45,45);
    BtnPrev->setToolTip(tr("上一首"));
    BtnPrev->setCursor(QCursor(Qt::PointingHandCursor));

    BtnNext=new QPushButton(this);
    BtnNext->setObjectName(tr("BtnNext"));
    BtnNext->setGeometry(210,255,45,45);
    BtnNext->setToolTip(tr("下一首"));
    BtnNext->setCursor(QCursor(Qt::PointingHandCursor));

    muteButton=new QPushButton(this);
    muteButton->setObjectName(tr("muteButton"));
    muteButton->setGeometry(370,320,25,25);
    muteButton->setToolTip(tr("關閉聲音"));
    muteButton->setCursor(QCursor(Qt::PointingHandCursor));


    volumeControl=new QSlider(Qt::Vertical,this);//QSlider(Qt::Vertical,this)創建一個豎直方向的滑動條QSlider控制項
    volumeControl->setObjectName(tr("volumeControl"));
    volumeControl->setGeometry(375,240,15,80);
    volumeControl->setCursor(QCursor(Qt::PointingHandCursor));
    volumeControl->setRange(0,100);//設置滑動條控制項的最小值和最大值
    volumeControl ->setValue(50);//設置初值為50;

    seekSlider = new QSlider(Qt::Horizontal,this);//QSlider(Qt::Horizontal,this)創建一個水平方向的滑動條QSlider控制項
    seekSlider -> setGeometry(100,345,200,15);
    seekSlider->setObjectName(tr("seekSlider"));
    seekSlider -> setCursor(QCursor(Qt::PointingHandCursor));

    addMore = new QPushButton(this);
    addMore -> setGeometry(295,2,30,30);
    addMore -> setObjectName(tr("addMore"));
    addMore->setToolTip(tr("添加歌曲"));
    addMore -> setCursor(QCursor(Qt::PointingHandCursor));

    showMge = new QLabel(this);
    showMge -> setGeometry(34,320,400,20);
    showMge -> setFont(QFont("Times",10,QFont::Bold));//字體使用Times,10號字體,加粗
    QPalette pac;//創建調色板
    pac.setColor(QPalette::WindowText,QColor(70,80,70));
    showMge -> setPalette(pac);

    list = new QListWidget(this);
    list ->setGeometry(20,50,360,180);
    list -> setFont(QFont("Times",10,QFont::Bold));
    list -> setPalette(pac);
    list ->setStyleSheet("background: rgba(0,0,0,0.1);");


    message = new QLabel(this);
    message -> setGeometry(20,30,140,20);
    message -> setFont(QFont("Times",10,QFont::Bold));
    message -> setPalette(pac);

    showPro = new QLabel(this);
    showPro -> setGeometry(35,340,50,20);
    showPro -> setFont(QFont("Times",10,QFont::Bold));
    showPro -> setPalette(pac);
    QTime mov(0,0,0);
    showPro ->setText(mov.toString("mm:ss"));

    showTime = new QLabel(this);
    showTime -> setGeometry(325,340,50,20);
    showTime -> setFont(QFont("Times",10,QFont::Bold));
    showTime -> setPalette(pac);
    QTime mo(0,0,0);//QTime 提供時間函數給用戶使用
    showTime ->setText(mo.toString("mm:ss"));//顯示分:秒

    title = new QLabel(this);//設置標題
    title -> setGeometry(5,0,200,30);
    title ->setFont(QFont("Times",15,QFont::Bold));
    QPalette pa;
    pa.setColor(QPalette::WindowText,QColor(0,0,0));
    title -> setPalette(pa);
    title -> setText("MusicPlayer");



    //信號與槽
    connect(BtnClose, SIGNAL(clicked(bool)), this, SLOT(close()));
    connect(BtnMin, SIGNAL(clicked(bool)), this, SLOT(showMinimized()));
    connect(addMore, SIGNAL(clicked(bool)), this, SLOT(addMoremusic()));
    connect(BtnPlay, SIGNAL(clicked(bool)), this, SLOT(playMusic()));
    connect (BtnPrev,SIGNAL(clicked(bool)), this, SLOT(preMusic()));
    connect(BtnNext, SIGNAL(clicked(bool)), this, SLOT(nextMusic()));
    connect(muteButton, SIGNAL(clicked(bool)), this, SLOT(meteOpen()));
    connect(volumeControl, SIGNAL(sliderMoved(int)), this, SLOT(volumChange(int)));
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT( positionChange(qint64)));
    connect(playPattern,SIGNAL(clicked(bool)),this,SLOT(musicPlayPattern()));


}
View Code

但界面很醜,所以下一步就是載入qss文件,繪製界面樣式:

1 //外部載入qss文件,繪製界面樣式
2 void Music::init_skin()
3 {
4     QFile file(":/qss/skin.qss");
5     file.open(QFile::ReadOnly);
6     this -> setStyleSheet(QObject::tr(file.readAll()));
7     file.close();
8 
9 }

我的qss代碼如下(qss和css的語法幾乎一模一樣):

  1 QPushButton#playPattern:!hover
  2 {
  3         border-image: url(:/image/Seq.png);
  4 }
  5 QPushButton#playPattern:hover
  6 {
  7         border-image: url(:/image/Seq.png);
  8 }
  9 QPushButton#playPattern:pressed{
 10         border-image: url(:/image/Seq.png);
 11 }
 12 QPushButton#BtnClose:!hover
 13 {
 14         border-image: url(:/image/close.png);
 15 }
 16 QPushButton#BtnClose:hover
 17 {
 18         border-image: url(:/image/close.png);
 19 }
 20 QPushButton#BtnClose:pressed
 21 {
 22         border-image: url(:/image/close.png);
 23 }
 24 QPushButton#BtnClose:focus{padding:-1;}
 25 
 26 
 27 
 28 QPushButton#addMore
 29 {
 30         border-image: url(:/image/addMore.png);
 31 
 32 }
 33 
 34 
 35 QPushButton#BtnMin:!hover
 36 {
 37         border-image: url(:/image/min.png);
 38 }
 39 QPushButton#BtnMin:hover
 40 {
 41         border-image: url(:/image/min.png);
 42 }
 43 QPushButton#BtnMin:pressed
 44 {
 45         border-image: url(:/image/min.png);
 46 }
 47 QPushButton#BtnMin:focus{padding:-1;}
 48 
 49 
 50 QPushButton#BtnPlay:!hover
 51 {
 52         border-image: url(:/image/play_hover.png);
 53 }
 54 QPushButton#BtnPlay:hover
 55 {
 56         border-image: url(:/image/play_hover.png);
 57 }
 58 QPushButton#BtnPlay:pressed
 59 {
 60         border-image: url(:/image/play_press.png);
 61 }
 62 QPushButton#BtnPlay:focus
 63 {
 64         padding:-1;
 65 }
 66 
 67 QPushButton#BtnPrev:!hover
 68 {
 69         border-image: url(:/image/prev_hover.png);
 70 }
 71 QPushButton#BtnPrev:hover
 72 {
 73         border-image: url(:/image/prev_hover.png);
 74 }
 75 QPushButton#BtnPrev:pressed
 76 {
 77         border-image: url(:/image/prev_press.png);
 78 }
 79 QPushButton#BtnPrev:focus{padding:-1;}
 80 
 81 QPushButton#BtnNext:!hover
 82 {
 83         border-image: url(:/image/next_hover.png);
 84 }
 85 QPushButton#BtnNext:hover
 86 {
 87         border-image: url(:/image/next_hover.png);
 88 }
 89 QPushButton#BtnNext:pressed
 90 {
 91         border-image: url(:/image/next_press.png);
 92 }
 93 QPushButton#BtnNext:focus{padding:-1;}
 94 
 95 
 96 QPushButton#muteButton:!hover
 97 {
 98         border-image: url(:/image/sound.png);
 99  }
100 QPushButton#muteButton:hover
101 {
102         border-image: url(:/image/sound.png);
103 }
104 QPushButton#muteButton:pressed
105 {
106         border-image: url(:/image/sound_close.png);
107 }
108 QPushButton#muteButton:focus{padding:-1;}
109 
110 
111 
112 QSlider#volumeControl::groove:Vertical {
113         border: 0px solid #bbb;
114         background: rgba(0,0,0,0.1);
115         width: 4px;
116         border-radius: 1px;
117 }
118 
119 QSlider#volumeControl::sub-page:Vertical {
120         background: rgba(0,0,0,0.1);
121         border: 0px solid #777;
122         width: 4px;
123         border-radius: 1px;
124 }
125 
126 QSlider#volumeControl::add-page:Vertical {
127         background:url(:/image/progress_sound.bmp);
128         border: 0px solid #777;
129         width: 4px;
130         border-radius: 1px;
131 }
132 
133 QSlider#volumeControl::handle:Vertical {
134         border-image:url(:/image/progress_thume.png);
135         border: 0px solid #777;
136         width: 28px;
137         height: 28px;
138         margin-left:-12px;
139         margin-right:-12px;
140         margin-top: -12px;
141         margin-bottom: -12px;
142         border-radius: 4px;
143 }
144 
145 
146 QSlider#seekSlider::groove:horizontal {
147         border-left:-14px solid;
148         background: rgba(0,0,0,0.1);
149         height: 4px;
150         border-radius: 4px;
151 }
152 
153 QSlider#seekSlider::sub-page:horizontal {
154         background:url(:/image/progress.bmp);
155         border: 0px solid #777;
156         height: 4px;
157         border-radius: 4px;
158 }
159 
160 QSlider#seekSlider::add-page:horizontal {
161         background: rgba(0,0,0,0.1);
162         border: 0px solid #777;
163         height: 4px;
164         border-radius:4px;
165 }
166 
167 QSlider#seekSlider::handle:horizontal {
168         background:url(:/image/progress_thume.png);
169         border: 0px solid #777;
170         width: 28px;
171         height: 28px;
172         border-left:0px;
173         border-right:0px;
174         margin-left:2px;
175         margin-right:-12px;
176         margin-top: -12px;
177         margin-bottom: -12px;
178         border-radius: 4px;
179 }
View Code

這樣樣式就已經基本搞定了,只剩下寫槽函數來實現具體功能了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. Ubuntu16.04上使用sudo apt-get install php7.1 安裝php的預設路徑如下: a. php可執行命令:/usr/bin/php7.1 和 /usr/bin/php b. 需要安裝sudo apt install php7.1-dev 才會有 /usr/bin/ ...
  • 導讀: 1.變數和對象 2.可變對象與不可變對象 3.引用傳參 在C/C++中,傳值和傳引用是函數參數傳遞的兩種方式。由於思維定式,從C/C++轉過來的Python初學者也經常會感到疑惑:在Python中,函數參數傳遞是傳值,還是傳引用呢?看下麵兩段代碼: 看完第一段代碼,會有人說這是值傳遞,因為函 ...
  • Q: 棧、隊列與數組的區別? A: 本篇主要涉及三種數據存儲類型:棧、隊列和優先順序隊列,它與數組主要有如下三個區別: A: (一)程式員工具 數組和其他的結構(棧、隊列、鏈表、樹等等)都適用於資料庫應用中作為數據記錄。它們常用於記錄那些對應於現實世界的對象和活動的數據,如職員檔案等,這些結構便於數據 ...
  • 判斷cookie是否為空非常重要,因為第一次訪問的時候為空會發生空指針異常。 註意對request和response的亂碼問題進行處理 註意連接c3p0時需要的jar包、工具類以及配置文件 ...
  • 傳說學java的圈子裡面存在著這樣一個鄙視鏈:電腦專業科班出身的鄙視自學java的,自學java的鄙視參加java培訓的。主要是他們覺得明明現在互聯網這麼發達,網上到處都是java學習資料,比如各種免費的java視頻教程、書籍,去參加java培訓班簡直就是浪費錢嘛!但為什麼還是有那麼多人要去參加j ...
  • 最近寫了一個爬蟲,需要連接國外的一個網站,經常出現掉線的情況,自己寫了一個自動重連的代碼,但感覺不夠簡潔。。。 後來就上萬能的github,找到了一個第三包,基本能滿足我的要求。這個第三方包就是retrying. 我的需求就是每當出現request相關異常的時候,就自動重來,上限連接10次;使用代碼 ...
  • 今天想自己搭一個blog網站,由於之前一直使用Java開發伺服器,並且使用的是nginx,所以沒有搭建PHP的運行環境。於是決定寫下這篇博文與大家一起分享一下。 先介紹一下使用的環境:centos 7.4, PHP 7.0 , nginx 1.12 不同的系統版本可能配置有些稍微不同,請大家配置的時 ...
  • 封裝性(有時稱為數據隱藏)。實現封裝的關鍵在於絕對不能讓類中的方法直接地訪問其他類的實例域值。程式僅通過對象的方法與對象的數據進行交互。給對象賦予了“黑盒”的特征,提高了重用性和可靠性。簡而言之,就是只需知道方法對應的作用,而不必瞭解它的具體實現過程。 實例域 私有數據域即寫在全局的私有變數或常量。 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...