多媒体

多媒体(Multimedia)是多种媒体的综合,一般包括文本,声音和图像等多种媒体形式。

在计算机系统中,多媒体指组合两种或两种以上媒体的一种人机交互式信息交流和传播媒体。
使用的媒体包括文字、图片、照片、声音、动画和影片,以及程式所提供的互动功能。
Qt 的多媒体模块提供了音频、视频、录音、摄像头拍照和录像等功能。本章将介绍 Qt 多
媒体的功能和使用。

Qt 多媒体简介

Qt 从 4.4 版本开始提供的一套多媒体框架,提供多媒体回放的功能。在 Qt 4.6 中实现多媒
体播放图形界面主要依赖 phonon 框架。phonon 最初是 一个 源于 KDE 的项目,为使用音频和
视频的应用程序开发提供的一个框架。应用程序不用去管多媒体播放是通过什么实现的(如

gstreamer、xine),只需调用相应的接口就行,但这中间需要一个中转,被称为 backend。Qt 也
是通过 phonon 来实现跨平台的多媒体播放。

从 Qt5 开始,Qt 就弃用了 phonon,直接使用 Qt Multimedia 模块。我们可以 Qt Multimedia

模块来提供的类实现跨平台的多媒体播放了。使用 Qt Multimedia 就不需要中转了,但是底层还
是需要多媒体插件实现的。Qt 只是提供多媒体接口,播放多媒体实际上是通过多媒体插件实现
的,我们不需要管这些插件是什么,Qt 在不同平台使用的多媒体插件不同。本章将会介绍如何
在 Windows 和 Linux 安装多媒体插件,Mac 系统不考虑,笔者条件有限!
Qt 多媒体模块提供了很多类,主要有 QMediaPlayer,QSound、QSoundEffect、QAudioOutput、

QAudioInput、QAudioRecorder、QVideoWidget 等等。类太多了不一一作解释,可以直接复制名
字到 Qt 的帮助文档里查看该解释。可以从名称大概了解它们是什么意思,具体类的使用直接看
本章的例子。

想要在 Qt 里使用使用 Qt 多媒体模块,需要在 pro 项目文件里添加如下语句。
QT += multimedia

注意:Qt 中的音乐播放器与视频播放器需要在 Ubuntu 里安装媒体解码器才能实现播放。

 Ubuntu16 / Ubuntu18,需要安装以下插件。播放音乐需要安装 Gst 解码插件。需要在终端
输入如下指令,注意不要复制错误了,下面指令已经在 Ubuntu16/Ubuntu18 测试成功,如
果读者 Ubuntu 没有配置网络与源服务器,这些导致安装不成功与本教程无关,确实需要
读者好好打下 Ubuntu 操作的基础了!

sudo apt-get install gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gstreamer1.0-plugins-good
gstreamer1.0-plugins-ugly gstreamer1.0-pulseaudio gstreamer1.0-libav

 Windows 需要安装如 LAVFilters 解码器,只需要百度 LAVFilters,找到 LAVFilters 官网下载此
软件即可,当然本教程的资料会提供一份 LAVFilters 的安装包。点击页脚下方的程序下载链
接跳转到下载本教程所有资料下载地址处,在顶层目录下。

音效文件播放

播放音效文件,比如简短的提示音(按键音等),可以使用 Qt 的 QSoundEffect 和 QSound

类来播放。
Qt 的 QSoundEffect 和 QSound 类主要区别是 QSoun(d 异步方式播放)只能播放本地的 WAV

音效文件(WAV 音效文件是 PC 机上最为流行的声音文件格式,但其文件尺寸较大,多用于存
储简短的声音片段,具有低延时性,不失真的特点),QSoundEffect 不仅可以播放网络文件,也
可以播放本地音效文件,播放网络的文件一般使用到 QUrl 链接。

应用实例

本例目的:了解 QSound 类的使用。

例 13_button_sound,按钮音效测试(难度:一般)。项目路径为 Qt/2/13_button_sound。本
例大体流程,通过点击一个按钮,然后使用 QSound 来播放音效文件,模仿按键按下的声音。

项目文件 13_button_sound.pro 文件第一行添加的代码部分如下。

13_button_sound.pro 编程后的代码

1 QT += core gui multimedia 2 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 5 CONFIG += c++11 6 7 # The following define makes your compiler emit warnings if you use 8 # any Qt feature that has been marked deprecated (the exact warnings 9 # depend on your compiler). Please consult the documentation of the 10 # deprecated API in order to know how to port your code away from it. 11 DEFINES += QT_DEPRECATED_WARNINGS 12 13 # You can also make your code fail to compile if it uses deprecated APIs. 14 # In order to do so, uncomment the following line. 15 # You can also select to disable deprecated APIs only up to a certain
version of Qt. 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the
APIs deprecated before Qt 6.0.0 17 18 SOURCES += \ 19 main.cpp \ 20 mainwindow.cpp 21 22 HEADERS += \ 23 mainwindow.h 24 25 # Default rules for deployment. 26 qnx: target.path = /tmp/$${TARGET}/bin 27 else: unix:!android: target.path = /opt/$${TARGET}/bin 28 !isEmpty(target.path): INSTALLS += target 29 30 RESOURCES += \ 31 src.qrc

在头文件“mainwindow.h”具体代码如下。

mainwindow.h 编程后的代码

 /****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName 13_button_sound * @brief mainwindow.h * @author Deng Zhimao * @email 1252699831@qq.com * @net www.openedv.com * @date 2021-04-20 *******************************************************************/ 1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QSound> 6 #include <QPushButton> 7 8 class MainWindow : public QMainWindow 9 { 10 Q_OBJECT 11 12 public: 13 MainWindow(QWidget *parent = nullptr); 14 ~MainWindow(); 15 16 private: 17 /* 按钮 */ 18 QPushButton *pushButton; 19 20 private slots: 21 /* 按钮点击槽函数 */ 22 void pushButtonClicked(); 23 24 }; 25 #endif // MAINWINDOW_H 26

头文件里主要是声明界面使用的一个按钮,及按钮槽函数。

在源文件“mainwindow.cpp”具体代码如下。

mainwindow.cpp 编程后的代码

 /****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName 13_button_sound * @brief mainwindow.cpp * @author Deng Zhimao * @email 1252699831@qq.com
* @net www.openedv.com * @date 2021-04-20 *******************************************************************/ 1 #include "mainwindow.h" 2 3 MainWindow::MainWindow(QWidget *parent) 4 : QMainWindow(parent) 5 { 6 /* 设置主窗体的位置与大小 */ 7 this->setGeometry(0, 0, 800, 480); 8 9 /* 实例化按钮 */ 10 pushButton = new QPushButton(this); 11 12 /* 设置按钮文本 */ 13 pushButton->setText("按钮音效测试"); 14 15 /* 设置按钮的位置与大小 */ 16 pushButton->setGeometry(340, 220, 120, 40); 17 18 /* 信号槽连接 */ 19 connect(pushButton, SIGNAL(clicked()), 20 this, SLOT(pushButtonClicked())); 21 } 22 23 MainWindow::~MainWindow() 24 { 25 } 26 27 void MainWindow::pushButtonClicked() 28 { 29 /* 异步的方式播放 */ 30 QSound::play(":/audio/bell.wav"); 31 }

第 30 行,直接使用 QSound 的静态函数 play()播放,这种播放方式是异步的,可以多次点
击按钮连续听到点击的声音。

程序运行效果

单击按钮后,可以听到播放 1 秒左右的叮咚声,用此方法来模拟单击按钮声音效果。

音乐播放器

QMediaPlayer 类是一个高级媒体播放类。它可以用来播放歌曲、电影和网络广播等内容。
一般用于播放 mp3 和 mp4 等等媒体文件。QMediaPlayer 类常常与 QMediaPlaylist 类一起使用。
可以很轻松的设计一个自己喜欢的音乐播放器与视频播放器。
QMediaPlayer 提供了很多信号,我们可以使用这些信号来完成音乐播放器的一系列操作,
比如媒体状态改变的信号 stateChanged(QMediaPlayer::State state),判断这个 state 的状态就可以
知道什么时候媒体暂停、播放、停止了。Qt 在媒体播放类已经提供了很多功能函数给我们使用,
像直接使用 play()函数就可以实现音乐文件的播放,前提我们需要知道媒体文件的路径。pause()

函数可以直接暂停媒体播放等等,这些都可以在 Qt 帮助文档里查看 QMediaPlayer 类的使用方
法就可以知道。不再一一列出。

应用实例

本例设计一个比较好看的音乐播放器,界面是笔者模仿网上的一个音乐播放器的界面,并
非笔者原创界面,只是笔者用 Qt 实现了网上的一个好看的音乐播放器界面。其中本例有些功能
并没有完善,比如播放模式、没有加音量控制等。这些可以由读者自由完善,比较简单。

本例目的:音乐播放器的设计与使用。

例 14_musicplayer,音乐播放器(难度:中等)。项目路径为 Qt/2/14_musicplayer。注意本
例有用到 qss 样式文件,关于如何添加资源文件与 qss 文件请参考 7.1.3 小节。音乐播放器的功
能这些都为大家所熟知,不用笔者介绍了。

项目文件 14_musicplayer.pro 文件第一行添加的代码部分如下。

14_musicplayer.pro 编程后的代码

1 QT += core gui multimedia 2 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 5 CONFIG += c++11 6 7 # The following define makes your compiler emit warnings if you use 8 # any Qt feature that has been marked deprecated (the exact warnings 9 # depend on your compiler). Please consult the documentation of the 10 # deprecated API in order to know how to port your code away from it. 11 DEFINES += QT_DEPRECATED_WARNINGS 12 13 # You can also make your code fail to compile if it uses deprecated APIs. 14 # In order to do so, uncomment the following line. 15 # You can also select to disable deprecated APIs only up to a certain
version of Qt. 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the
APIs deprecated before Qt 6.0.0 17 18 SOURCES += \ 19 main.cpp \ 20 mainwindow.cpp 21 22 HEADERS += \ 23 mainwindow.h 24 25 # Default rules for deployment. 26 qnx: target.path = /tmp/$${TARGET}/bin 27 else: unix:!android: target.path = /opt/$${TARGET}/bin 28 !isEmpty(target.path): INSTALLS += target 29 30 RESOURCES += \ 31 res.qrc

在头文件“mainwindow.h”具体代码如下。

mainwindow.h 编程后的代码

 /****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName 14_musicplayer * @brief mainwindow.h * @author Deng Zhimao * @email 1252699831@qq.com * @net www.openedv.com * @date 2021-04-20 *******************************************************************/
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QMediaPlayer> 6 #include <QMediaPlaylist> 7 #include <QPushButton> 8 #include <QSlider> 9 #include <QVBoxLayout> 10 #include <QHBoxLayout> 11 #include <QListWidget> 12 #include <QLabel> 13 #include <QSpacerItem> 14 #include <QDebug> 15 16 /* 媒体信息结构体 */ 17 struct MediaObjectInfo { 18 /* 用于保存歌曲文件名 */ 19 QString fileName; 20 /* 用于保存歌曲文件路径 */ 21 QString filePath; 22 }; 23 24 class MainWindow : public QMainWindow 25 { 26 Q_OBJECT 27 28 public: 29 MainWindow(QWidget *parent = nullptr); 30 ~MainWindow(); 31 32 private: 33 /* 媒体播放器,用于播放音乐 */ 34 QMediaPlayer *musicPlayer; 35 36 /* 媒体列表 */ 37 QMediaPlaylist *mediaPlaylist; 38 39 /* 音乐列表 */ 40 QListWidget *listWidget; 41 42 /* 播放进度条 */ 43 QSlider *durationSlider; 44 45 /* 音乐播放器按钮 */ 46 QPushButton *pushButton[7]; 47 48 /* 垂直布局 */ 49 QVBoxLayout *vBoxLayout[3]; 50 51 /* 水平布局 */ 52 QHBoxLayout *hBoxLayout[4]; 53 54 /* 垂直容器 */ 55 QWidget *vWidget[3]; 56 57 /* 水平容器 */ 58 QWidget *hWidget[4]; 59 60 /* 标签文本 */ 61 QLabel *label[4]; 62 63 /* 用于遮罩 */ 64 QWidget *listMask; 65 66 /* 音乐布局函数 */ 67 void musicLayout(); 68 69 /* 主窗体大小重设大小函数重写 */ 70 void resizeEvent(QResizeEvent *event); 71 72 /* 媒体信息存储 */ 73 QVector<MediaObjectInfo> mediaObjectInfo; 74 75 /* 扫描歌曲 */ 76 void scanSongs(); 77 78 /* 媒体播放器类初始化 */ 79 void mediaPlayerInit(); 80 81 private slots: 82 /* 播放按钮点击 */ 83 void btn_play_clicked(); 84 85 /* 下一曲按钮点击*/86 void btn_next_clicked(); 87 88 /* 上一曲按钮点击 */ 89 void btn_previous_clicked(); 90 91 /* 媒体状态改变 */ 92 void mediaPlayerStateChanged(QMediaPlayer::State); 93 94 /* 列表单击 */ 95 void listWidgetCliked(QListWidgetItem*); 96 97 /* 媒体列表项改变 */ 98 void mediaPlaylistCurrentIndexChanged(int); 99 100 /* 媒体总长度改变 */ 101 void musicPlayerDurationChanged(qint64); 102 103 /* 媒体播放位置改变 */ 104 void mediaPlayerPositionChanged(qint64); 105 106 /* 播放进度条松开 */ 107 void durationSliderReleased(); 108 }; 109 #endif // MAINWINDOW_H

头文件里主要是声明界面所使用的元素及一些槽函数。

在源文件“mainwindow.cpp”具体代码如下。

mainwindow.cpp 编程后的代码

 /****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName 14_musicplayer * @brief mainwindow.cpp * @author Deng Zhimao * @email 1252699831@qq.com * @net www.openedv.com * @date 2021-04-20 *******************************************************************/ 1 #include "mainwindow.h" 2 #include <QCoreApplication> 3 #include <QFileInfoList> 4 #include <QDir> 5 6 MainWindow::MainWindow(QWidget *parent) 7 : QMainWindow(parent) 8 { 9 /* 布局初始化 */ 10 musicLayout(); 11 12 /* 媒体播放器初始化 */ 13 mediaPlayerInit(); 14 15 /* 扫描歌曲 */ 16 scanSongs(); 17 18 /* 按钮信号槽连接 */ 19 connect(pushButton[0], SIGNAL(clicked()), 20 this, SLOT(btn_previous_clicked())); 21 connect(pushButton[1], SIGNAL(clicked()), 22 this, SLOT(btn_play_clicked())); 23 connect(pushButton[2], SIGNAL(clicked()), 24 this, SLOT(btn_next_clicked())); 25 26 /* 媒体信号槽连接 */ 27 connect(musicPlayer, 28 SIGNAL(stateChanged(QMediaPlayer::State)), 29 this, 30 SLOT(mediaPlayerStateChanged(QMediaPlayer::State))); 31 connect(mediaPlaylist, 32 SIGNAL(currentIndexChanged(int)), 33 this, 34 SLOT(mediaPlaylistCurrentIndexChanged(int))); 35 connect(musicPlayer, SIGNAL(durationChanged(qint64)), 36 this, 37 SLOT(musicPlayerDurationChanged(qint64))); 38 connect(musicPlayer, 39 SIGNAL(positionChanged(qint64)), 40 this, 41 SLOT(mediaPlayerPositionChanged(qint64))); 42 43 /* 列表信号槽连接 */ 44 connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)), 45 this, SLOT(listWidgetCliked(QListWidgetItem*))); 46 47 /* slider 信号槽连接 */ 48 connect(durationSlider, SIGNAL(sliderReleased()), 49 this, SLOT(durationSliderReleased())); 51 /* 失去焦点 */ 52 this->setFocus(); 53 } 54 55 void MainWindow::musicLayout() 56 { 57 /* 设置位置与大小,这里固定为 800, 480 */ 58 this->setGeometry(0, 0, 800, 480); 59 QPalette pal; 60 61 /* 按钮 */ 62 for (int i = 0; i < 7; i++) 63 pushButton[i] = new QPushButton(); 64 65 /* 标签 */ 66 for (int i = 0; i < 4; i++) 67 label[i] = new QLabel(); 68 69 for (int i = 0; i < 3; i++) { 70 /* 垂直容器 */ 71 vWidget[i] = new QWidget(); 72 vWidget[i]->setAutoFillBackground(true); 73 /* 垂直布局 */ 74 vBoxLayout[i] = new QVBoxLayout(); 75 } 76 77 for (int i = 0; i < 4; i++) { 78 /* 水平容器 */ 79 hWidget[i] = new QWidget(); 80 hWidget[i]->setAutoFillBackground(true); 81 /* 水平布局 */ 82 hBoxLayout[i] = new QHBoxLayout(); 83 } 84 85 /* 播放进度条 */ 86 durationSlider = new QSlider(Qt::Horizontal); 87 durationSlider->setMinimumSize(300, 15); 88 durationSlider->setMaximumHeight(15); 89 durationSlider->setObjectName("durationSlider"); 90 91 /* 音乐列表 */ 92 listWidget = new QListWidget(); 93 listWidget->setObjectName("listWidget"); 94 listWidget->resize(310, 265); 95 listWidget->setVerticalScrollBarPolicy( 96 Qt::ScrollBarAlwaysOff); 97 listWidget->setHorizontalScrollBarPolicy( 98 Qt::ScrollBarAlwaysOff); 99 100 /* 列表遮罩 */ 101 listMask = new QWidget(listWidget); 102 listMask->setMinimumSize(310, 50); 103 listMask->setMinimumHeight(50); 104 listMask->setObjectName("listMask"); 105 listMask->setGeometry(0, 106 listWidget->height() - 50, 107 310, 108 50); 109 110 /* 设置对象名称 */ 111 pushButton[0]->setObjectName("btn_previous"); 112 pushButton[1]->setObjectName("btn_play"); 113 pushButton[2]->setObjectName("btn_next"); 114 pushButton[3]->setObjectName("btn_favorite"); 115 pushButton[4]->setObjectName("btn_mode"); 116 pushButton[5]->setObjectName("btn_menu"); 117 pushButton[6]->setObjectName("btn_volume"); 118 119 /* 设置按钮属性 */ 120 pushButton[1]->setCheckable(true); 121 pushButton[3]->setCheckable(true); 122 123 /* H0 布局 */ 124 vWidget[0]->setMinimumSize(310, 480); 125 vWidget[0]->setMaximumWidth(310); 126 vWidget[1]->setMinimumSize(320, 480); 127 QSpacerItem *hSpacer0 = new 128 QSpacerItem(70, 480, 129 QSizePolicy::Minimum, 130 QSizePolicy::Maximum); 131 132 QSpacerItem *hSpacer1 = new 133 QSpacerItem(65, 480, 134 QSizePolicy::Minimum, 135 QSizePolicy::Maximum); 136 137 QSpacerItem *hSpacer2 = new 138 QSpacerItem(60, 480, 139 QSizePolicy::Minimum, 140 QSizePolicy::Maximum); 141 142 hBoxLayout[0]->addSpacerItem(hSpacer0); 143 hBoxLayout[0]->addWidget(vWidget[0]); 144 hBoxLayout[0]->addSpacerItem(hSpacer1); 145 hBoxLayout[0]->addWidget(vWidget[1]); 146 hBoxLayout[0]->addSpacerItem(hSpacer2); 147 hBoxLayout[0]->setContentsMargins(0, 0, 0, 0); 148 149 hWidget[0]->setLayout(hBoxLayout[0]); 150 setCentralWidget(hWidget[0]); 151 152 /* V0 布局 */ 153 listWidget->setMinimumSize(310, 265); 154 hWidget[1]->setMinimumSize(310, 80); 155 hWidget[1]->setMaximumHeight(80); 156 label[0]->setMinimumSize(310, 95); 157 label[0]->setMaximumHeight(95); 158 QSpacerItem *vSpacer0 = new 159 QSpacerItem(310, 10, 160 QSizePolicy::Minimum, 161 QSizePolicy::Maximum); 162 QSpacerItem *vSpacer1 = new 163 QSpacerItem(310, 30, 164 QSizePolicy::Minimum, 165 QSizePolicy::Minimum); 166 vBoxLayout[0]->addWidget(label[0]); 167 vBoxLayout[0]->addWidget(listWidget); 168 vBoxLayout[0]->addSpacerItem(vSpacer0); 169 vBoxLayout[0]->addWidget(hWidget[1]); 170 vBoxLayout[0]->addSpacerItem(vSpacer1); 171 vBoxLayout[0]->setContentsMargins(0, 0, 0, 0); 172 173 vWidget[0]->setLayout(vBoxLayout[0]); 174 175 /* H1 布局 */ 176 for (int i = 0; i < 3; i++) { 177 pushButton[i]->setMinimumSize(80, 80); 178 } 179 QSpacerItem *hSpacer3 = new 180 QSpacerItem(40, 80, 181 QSizePolicy::Expanding, 182 QSizePolicy::Expanding); 183 QSpacerItem *hSpacer4 = new 184 QSpacerItem(40, 80, 185 QSizePolicy::Expanding, 186 QSizePolicy::Expanding); 187 hBoxLayout[1]->addWidget(pushButton[0]); 188 hBoxLayout[1]->addSpacerItem(hSpacer3); 189 hBoxLayout[1]->addWidget(pushButton[1]); 190 hBoxLayout[1]->addSpacerItem(hSpacer4); 191 hBoxLayout[1]->addWidget(pushButton[2]); 192 hBoxLayout[1]->setContentsMargins(0, 0, 0, 0); 193 194 hWidget[1]->setLayout(hBoxLayout[1]); 195 196 /* V1 布局 */ 197 QSpacerItem *vSpacer2 = new 198 QSpacerItem(320, 40, 199 QSizePolicy::Minimum, 200 QSizePolicy::Maximum); 201 QSpacerItem *vSpacer3 = new 202 QSpacerItem(320, 20, 203 QSizePolicy::Minimum, 204 QSizePolicy::Maximum); 205 QSpacerItem *vSpacer4 = new 206 QSpacerItem(320, 30, 207 QSizePolicy::Minimum, 208 QSizePolicy::Minimum); 209 label[1]->setMinimumSize(320, 320); 210 QImage Image; 211 Image.load(":/images/cd.png"); 212 QPixmap pixmap = QPixmap::fromImage(Image); 213 int with = 320; 214 int height = 320; 215 QPixmap fitpixmap = 216 pixmap.scaled(with, height, 217 Qt::IgnoreAspectRatio, 218 Qt::SmoothTransformation); 219 label[1]->setPixmap(fitpixmap); 220 label[1]->setAlignment(Qt::AlignCenter); 221 vWidget[2]->setMinimumSize(300, 80); 222 vWidget[2]->setMaximumHeight(80); 223 vBoxLayout[1]->addSpacerItem(vSpacer2); 224 vBoxLayout[1]->addWidget(label[1]); 225 vBoxLayout[1]->addSpacerItem(vSpacer3); 226 vBoxLayout[1]->addWidget(durationSlider); 227 vBoxLayout[1]->addWidget(vWidget[2]); 228 vBoxLayout[1]->addSpacerItem(vSpacer4); 229 vBoxLayout[1]->setContentsMargins(0, 0, 0, 0); 230 231 vWidget[1]->setLayout(vBoxLayout[1]); 232 233 /* V2 布局 */ 234 QSpacerItem *vSpacer5 = new 235 QSpacerItem(300, 10, 236 QSizePolicy::Minimum, 237 QSizePolicy::Maximum); 238 hWidget[2]->setMinimumSize(320, 20); 239 hWidget[3]->setMinimumSize(320, 60); 240 vBoxLayout[2]->addWidget(hWidget[2]); 241 vBoxLayout[2]->addSpacerItem(vSpacer5); 242 vBoxLayout[2]->addWidget(hWidget[3]); 243 vBoxLayout[2]->setContentsMargins(0, 0, 0, 0); 244 245 vWidget[2]->setLayout(vBoxLayout[2]); 246 247 /* H2 布局 */ 248 label[2]->setText("00:00"); 249 label[3]->setText("00:00"); 250 QFont font; 251 252 font.setPixelSize(10); 253 254 /* 设置标签文本 */ 255 label[0]->setText("Q Music,Enjoy it!"); 256 label[2]->setText("00:00"); 257 label[3]->setText("00:00"); 258 label[2]->setSizePolicy(QSizePolicy::Expanding, 259 QSizePolicy::Expanding); 260 label[3]->setSizePolicy(QSizePolicy::Expanding, 261 QSizePolicy::Expanding); 262 label[3]->setAlignment(Qt::AlignRight); 263 label[2]->setAlignment(Qt::AlignLeft); 264 label[2]->setFont(font); 265 label[3]->setFont(font); 266 267 pal.setColor(QPalette::WindowText, Qt::white); 268 label[0]->setPalette(pal); 269 label[2]->setPalette(pal); 270 label[3]->setPalette(pal); 271 272 hBoxLayout[2]->addWidget(label[2]); 273 hBoxLayout[2]->addWidget(label[3]); 274 275 hBoxLayout[2]->setContentsMargins(0, 0, 0, 0); 276 hWidget[2]->setLayout(hBoxLayout[2]); 277 278 /* H3 布局 */ 279 QSpacerItem *hSpacer5 = new 280 QSpacerItem(0, 60, 281 QSizePolicy::Minimum, 282 QSizePolicy::Maximum); 283 QSpacerItem *hSpacer6 = new 284 QSpacerItem(80, 60, 285 QSizePolicy::Maximum, 286 QSizePolicy::Maximum); 287 QSpacerItem *hSpacer7 = new 288 QSpacerItem(80, 60, 289 QSizePolicy::Maximum, 290 QSizePolicy::Maximum); 291 QSpacerItem *hSpacer8 = new 292 QSpacerItem(80, 60, 293 QSizePolicy::Maximum, 294 QSizePolicy::Maximum); 295 QSpacerItem *hSpacer9 = new 296 QSpacerItem(0, 60, 297 QSizePolicy::Minimum, 298 QSizePolicy::Maximum); 299 300 for (int i = 3; i < 7; i++) { 301 pushButton[i]->setMinimumSize(25, 25); 302 pushButton[i]->setMaximumSize(25, 25); 303 } 304 305 hBoxLayout[3]->addSpacerItem(hSpacer5); 306 hBoxLayout[3]->addWidget(pushButton[3]); 307 hBoxLayout[3]->addSpacerItem(hSpacer6); 308 hBoxLayout[3]->addWidget(pushButton[4]); 309 hBoxLayout[3]->addSpacerItem(hSpacer7); 310 hBoxLayout[3]->addWidget(pushButton[5]); 311 hBoxLayout[3]->addSpacerItem(hSpacer8); 312 hBoxLayout[3]->addWidget(pushButton[6]); 313 hBoxLayout[3]->addSpacerItem(hSpacer9); 314 hBoxLayout[3]->setContentsMargins(0, 0, 0, 0); 315 hBoxLayout[3]->setAlignment(Qt::AlignHCenter); 316 317 hWidget[3]->setLayout(hBoxLayout[3]); 318 319 //hWidget[0]->setStyleSheet("background-color:red"); 320 //hWidget[1]->setStyleSheet("background-color:#ff5599"); 321 //hWidget[2]->setStyleSheet("background-color:#ff55ff"); 322 //hWidget[3]->setStyleSheet("background-color:black"); 323 //vWidget[0]->setStyleSheet("background-color:#555555"); 324 //vWidget[1]->setStyleSheet("background-color:green"); 325 //vWidget[2]->setStyleSheet("background-color:gray"); 326 327 } 328 329 MainWindow::~MainWindow() 330 { 331 } 332 333 void MainWindow::btn_play_clicked() 334 { 335 int state = musicPlayer->state(); 336 337 switch (state) { 338 case QMediaPlayer::StoppedState: 339 /* 媒体播放 */ 340 musicPlayer->play(); 341 break; 342 343 case QMediaPlayer::PlayingState: 344 /* 媒体暂停 */ 345 musicPlayer->pause(); 346 break; 347 348 case QMediaPlayer::PausedState: 349 musicPlayer->play(); 350 break; 351 } 352 } 353 354 void MainWindow::btn_next_clicked() 355 { 356 musicPlayer->stop(); 357 int count = mediaPlaylist->mediaCount(); 358 if (0 == count) 359 return; 360 361 /* 列表下一个 */ 362 mediaPlaylist->next(); 363 musicPlayer->play(); 364 } 365 366 void MainWindow::btn_previous_clicked() 367 { 368 musicPlayer->stop(); 369 int count = mediaPlaylist->mediaCount(); 370 if (0 == count) 371 return; 372 373 /* 列表上一个 */ 374 mediaPlaylist->previous(); 375 musicPlayer->play(); 376 } 377 378 void MainWindow::mediaPlayerStateChanged( 379 QMediaPlayer::State 380 state) 381 { 382 switch (state) { 383 case QMediaPlayer::StoppedState: 384 pushButton[1]->setChecked(false); 385 break; 386 387 case QMediaPlayer::PlayingState: 388 pushButton[1]->setChecked(true); 389 break; 390 391 case QMediaPlayer::PausedState: 392 pushButton[1]->setChecked(false); 393 break; 394 } 395 } 396 397 void MainWindow::listWidgetCliked(QListWidgetItem *item) 398 { 399 musicPlayer->stop(); 400 mediaPlaylist->setCurrentIndex(listWidget->row(item)); 401 musicPlayer->play(); 402 } 403 404 void MainWindow::mediaPlaylistCurrentIndexChanged( 405 int index) 406 { 407 if (-1 == index) 408 return; 409 410 /* 设置列表正在播放的项 */ 411 listWidget->setCurrentRow(index); 412 } 413 414 void MainWindow::musicPlayerDurationChanged( 415 qint64 duration) 416 { 417 durationSlider->setRange(0, duration / 1000); 418 int second = duration / 1000; 419 int minute = second / 60; 420 second %= 60; 421 422 QString mediaDuration; 423 mediaDuration.clear(); 424 425 if (minute >= 10) 426 mediaDuration = QString::number(minute, 10); 427 else 428 mediaDuration = "0" + QString::number(minute, 10); 429 430 if (second >= 10) 431 mediaDuration = mediaDuration 432 + ":" + QString::number(second, 10); 433 else 434 mediaDuration = mediaDuration 435 + ":0" + QString::number(second, 10); 436 437 /* 显示媒体总长度时间 */ 438 label[3]->setText(mediaDuration); 439 } 440 441 void MainWindow::mediaPlayerPositionChanged( 442 qint64 position) 443 { 444 if (!durationSlider->isSliderDown()) 445 durationSlider->setValue(position/1000); 446 447 int second = position / 1000; 448 int minute = second / 60; 449 second %= 60; 450 451 QString mediaPosition; 452 mediaPosition.clear(); 453 454 if (minute >= 10) 455 mediaPosition = QString::number(minute, 10); 456 else 457 mediaPosition = "0" + QString::number(minute, 10); 458 459 if (second >= 10) 460 mediaPosition = mediaPosition 461 + ":" + QString::number(second, 10); 462 else 463 mediaPosition = mediaPosition 464 + ":0" + QString::number(second, 10); 465 466 /* 显示现在播放的时间 */ 467 label[2]->setText(mediaPosition); 468 } 469 470 void MainWindow::resizeEvent(QResizeEvent *event) 471 { 472 Q_UNUSED(event); 473 listMask->setGeometry(0, 474 listWidget->height() - 50, 475 310, 476 50); 477 } 478 479 void MainWindow::durationSliderReleased() 480 { 481 /* 设置媒体播放的位置 */ 482 musicPlayer->setPosition(durationSlider->value() * 1000); 483 } 484 485 void MainWindow::scanSongs() 486 { 487 QDir dir(QCoreApplication::applicationDirPath() 488 + "/myMusic"); 489 QDir dirbsolutePath(dir.absolutePath()); 490 /* 如果目录存在 */ 491 if (dirbsolutePath.exists()) { 492 /* 定义过滤器 */ 493 QStringList filter; 494 /* 包含所有.mp3 后缀的文件 */ 495 filter << "*.mp3"; 496 /* 获取该目录下的所有文件 */ 497 QFileInfoList files = 498 dirbsolutePath.entryInfoList(filter, QDir::Files); 499 /* 遍历 */ 500 for (int i = 0; i < files.count(); i++) { 501 MediaObjectInfo info; 502 /* 使用 utf-8 编码 */ 503 QString fileName = QString::fromUtf8(files.at(i) 504 .fileName() 505 .replace(".mp3", "") 506 .toUtf8() 507 .data()); 508 info.fileName = fileName + "\n" 509 + fileName.split("-").at(1); 510 info.filePath = QString::fromUtf8(files.at(i) 511 .filePath() 512 .toUtf8() 513 .data()); 514 /* 媒体列表添加歌曲 */ 515 if (mediaPlaylist->addMedia( 516 QUrl::fromLocalFile(info.filePath))) { 517 /* 添加到容器数组里储存 */ 518 mediaObjectInfo.append(info); 519 /* 添加歌曲名字至列表 */ 520 listWidget->addItem(info.fileName); 521 } else { 522 qDebug()<< 523 mediaPlaylist->errorString() 524 .toUtf8().data() 525 << endl; 526 qDebug()<< " Error number:" 527 << mediaPlaylist->error() 528 << endl; 529 } 530 } 531 } 532 } 533 534 void MainWindow::mediaPlayerInit() 535 { 536 musicPlayer = new QMediaPlayer(this); 537 mediaPlaylist = new QMediaPlaylist(this); 538 /* 确保列表是空的 */ 539 mediaPlaylist->clear(); 540 /* 设置音乐播放器的列表为 mediaPlaylist */ 541 musicPlayer->setPlaylist(mediaPlaylist); 542 /* 设置播放模式,Loop 是列循环 */ 543 mediaPlaylist->setPlaybackMode(QMediaPlaylist::Loop); 544 }

第 10 行,布局初始化,第一步我们先建立好界面,确定好布局再实现功能,一般流程都这
样,布局 msuicLayout()的内容比较多,也不难,但是比较复杂,如果我们有第七章的基础,看
这种布局是没有难度的,这里就不多解释了。没有好看的布局也能完成本例。如果您喜欢这种
布局方法,您需要多花点时间去研究如何布局才好看,这些没有固定的方法,完全是一个人的
审美感。
第 13 行,媒体先初始化,初始化媒体播放器与媒体播放列表。
第 16 行,扫描歌曲,初始化本地歌曲,从固定的文件夹里找歌曲文件,这里笔者设计从固
定的文件夹里找歌曲文件。也有些读者可能会说可以自由选择文件夹吗?答案是可以的!使用

QFileDilog 类打开选择歌曲目录或者文件即可!但是在嵌入式里,一般是初始化界里面就已经
有歌曲在界面里的了,无需用户再去打开,打开歌曲这种操作是极少会使用的!
第 26 至 47 行,信号槽连接,这里使用了各种各样的信号。这里有必要说明一下,笔者设
计了单击歌曲列表就能播放歌曲了。如果在电脑上可能有些播放器软件会双击才能播放歌曲,
在嵌入式的触摸屏里,只有单击!没有双击,没有用户会双击歌曲的列表的。这些特殊的地方
我们需要在嵌入式里考虑!
第 333~376 行,点击播放按钮,上一曲,下一曲,Qt 的媒体类已经提供了 previous(),next(),

stop(),play(),pause()这些方法直接可以使用。除了实现好看的界面之外,这部分内容也是本
例实现播放器重要的部分!
其他部分是实现播放状态的切换及扩进度条的显示进度处理,请参阅源码理解。
main.cpp 内容如下,主要是加载 qss 样式文件。没有什么可讲解。

1 #include "mainwindow.h" 2 3 #include <QApplication> 4 #include <QFile> 5 6 int main(int argc, char *argv[]) 7 { 8 QApplication a(argc, argv); 9 /* 指定文件 */ 10 QFile file(":/style.qss"); 11 12 /* 判断文件是否存在 */ 13 if (file.exists() ) { 14 /* 以只读的方式打开 */ 15 file.open(QFile::ReadOnly); 16 /* 以字符串的方式保存读出的结果 */ 17 QString styleSheet = QLatin1String(file.readAll()); 18 /* 设置全局样式 */ 19 qApp->setStyleSheet(styleSheet); 20 /* 关闭文件 */ 21 file.close(); 22 } 23 24 MainWindow w; 25 w.show(); 26 return a.exec(); 27 }

style.qss 样式文件如下。素材已经在源码处提供。注意下面的 style.qss 不能有注释!

1 QWidget { 2 background: "#25242a" 3 } 4 5 QWidget#listMask { 6 border-image: url(:/images/mask.png); 7 background-color: transparent; 8 } 9 10 QListWidget#listWidget { 11 color:white; 12 font-size: 15px; 13 border:none; 14 } 15 16 QListWidget#listWidget:item:active { 17 background: transparent; 18 } 19 20 QListWidget#listWidget:item { 21 background: transparent; 22 height:60; 23 } 24 25 QListWidget#listWidget:item:selected { 26 color:#5edcf3; 27 background: transparent; 28 } 29 30 QListWidget#listWidget:item:hover { 31 background: transparent; 32 color:#5edcf3; 33 border:none; 34 } 35 36 QPushButton#btn_play { 37 border-image:url(:/images/btn_play1.png); 38 } 39 40 QPushButton#btn_play:hover { 41 border-image:url(:/images/btn_play2.png); 42 } 43 44 QPushButton#btn_play:checked { 45 border-image:url(:/images/btn_pause1.png); 46 } 47 48 QPushButton#btn_play:checked:hover { 49 border-image:url(:/images/btn_pause2.png); 50 } 51 52 QPushButton#btn_previous { 53 border-image:url(:/images/btn_previous1.png); 54 } 55 56 QPushButton#btn_previous:hover { 57 border-image:url(:/images/btn_previous2.png); 58 } 59 60 QPushButton#btn_next { 61 border-image:url(:/images/btn_next1.png); 62 } 63 64 QPushButton#btn_next:hover { 65 border-image:url(:/images/btn_next2.png); 66 } 67 68 QPushButton#btn_favorite { 69 border-image:url(:/images/btn_favorite_no.png); 70 } 71 72 QPushButton#btn_favorite:checked { 73 border-image:url(:/images/btn_favorite_yes.png); 74 } 75 76 QPushButton#btn_menu { 77 border-image:url(:/images/btn_menu1.png); 78 } 79 80 QPushButton#btn_menu:hover { 81 border-image:url(:/images/btn_menu2.png); 82 } 83 84 QPushButton#btn_mode { 85 border-image:url(:/images/btn_listcircle1.png); 86 } 87 88 QPushButton#btn_mode:hover { 89 border-image:url(:/images/btn_listcircle2.png); 90 } 91 92 QPushButton#btn_mode { 93 border-image:url(:/images/btn_listcircle1.png); 94 } 95 96 QPushButton#btn_mode:hover { 97 border-image:url(:/images/btn_listcircle2.png); 98 } 99 100 QPushButton#btn_volume { 101 border-image:url(:/images/btn_volume1.png); 102 } 103 104 QPushButton#btn_volume:hover { 105 border-image:url(:/images/btn_volume2.png); 106 } 107 108 QSlider#durationSlider:handle:horizontal { 109 border-image:url(:/images/handle.png); 110 } 111 112 QSlider#durationSlider:sub-page:horizontal { 113 border-image:url(:/images/sub-page.png); 114 }

程序运行效果

先点击构建项目,项目构建完成后,再将本例的 myMusic 歌曲文件夹拷贝到可执行程序的
文件夹同一级目录下,也就是 build-14_musicplayer-Desktop_Qt_5_12_9_GCC_64bit-Debug 目录
下(windows 需要进入到 debug 目录)。再点击运行,就出现歌曲在列表里,如下图,点击播放
即可播放歌曲,上一曲,下一曲也可以用。注意右下角的某些按钮功能,在本例没有继续去实
现,比如音量控制,可以直接加一个垂直方向的滑条,然后控制媒体的软件音量即可。留给读
者自由发挥,可以基于本例去开发,就当读者练习吧。本例的界面开发笔者还是比较满意的,
前面的界面都比较普通,笔者个人 Qt 开发重要的是界面与稳定性,功能是次要的!因为功能都
不难实现。

注意歌曲格式应严格为歌名 + “-” + 歌手名称.mp3,例如江南 - 林俊杰.mp3。中间的
“-”是英文字符的短横杠,这样的目的是能够将歌曲名称和歌手分开显示到界面上。

QT开发笔记(多媒体)相关推荐

  1. 【QT开发笔记-基础篇】| 第二章 常用控件 | 2.12 表格控件 QTableWidget

    本节对应的视频讲解:B_站_链_接 QTableWidget 是 Qt 中的表格控件,可以行列的形式来展示数据 1. 属性和方法 QTableWidget 有很多属性和方法,完整的可查看帮助文档. 在 ...

  2. Qt开发笔记(一):Qt+FFmpeg开发环境搭建以及工程模板

    原博主博客地址:https://blog.csdn.net/qq21497936 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/90 ...

  3. Matlab+Qt开发笔记(一):matlab搭建Qt开发matlib环境以及Demo测试

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/120979753 长期持续带来更多技术分享,定制咨询QQ ...

  4. Qt开发笔记之Qwt(一):Qwt介绍、编译与Demo

    若该文为原创文章,未经允许不得转载 原博主博客地址:长沙红胖子_长沙红胖子网络科技有限公司_CSDN博客 原博主博客导航:红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术.树莓派.三维.Op ...

  5. Qt开发笔记之Qwt(二):Qwt仪表盘的基本使用

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  6. 【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.1 效果演示、技术点

    本节对应的视频讲解:B_站_视_频 https://www.bilibili.com/video/BV14P4y197pi Qt 中绘图用到的类是 QPainter,可以实现点.线.矩形.圆形.多边形 ...

  7. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.2 搭建Qt开发环境

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1Pr4y1x7fh Qt 开发主要有两种开发环境 Qt Creator 它是 Qt 官方提供的开 ...

  8. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.1 为什么要学习Qt

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1334y1776z Qt 是一个跨平台的 C++ 图形用户界面应用程序框架 Qt 为应用程序开发 ...

  9. 【QT开发笔记-基础篇】| 第一章 QT入门 | 1.4 项目构建流程

    本节对应的视频讲解:B_站_链_接 https://www.bilibili.com/video/BV1cW4y1y7Lw 在上一节课中,我们新建了第一个 Qt 工程,其中包括 5 个文件: Hell ...

最新文章

  1. Quick-Cocos2d-x 集成 Google protobuf 方法
  2. PythonGuru 中文系列教程·翻译完成
  3. 搜狗Q1每天进账1886万,输入法日处理6亿请求成中国最大语音App
  4. UI Framework-1: Ash Color Chooser
  5. json解析库go-simplejson使用
  6. python查看类的属性和方法_python—类的属性和方法总结
  7. 电子设计竞赛技术报告格式
  8. kmeans聚类算法python实现_Python实现Kmeans聚类算法
  9. java socket发送json_Java中使用Socket发送Java对象实例
  10. 徐思201771010132《面向对象程序设计(java)》第一周学习总结
  11. 绝对干货的Twitter搜索技巧
  12. 不如意的人生,才是真实的。
  13. Centos 6.5安装最新版谷歌浏览器-Chrome
  14. smart210 dnw下载
  15. MySQL常规篇之增删改查(精选)
  16. MODBUS RTU协议
  17. 【SQL注入技巧拓展】————13、我的WafBypass之道(SQL注入篇)
  18. 自己不行就认为别人也不可能
  19. python中def fun()是什么意思_python学习函数
  20. 原生js自定义属性的操作:setAttribute、getAttribute、removeAttribute、hasAttribute

热门文章

  1. html日期备忘录插件,jQuery日历表设置日期备忘录代码
  2. 作为一个男人,尤其作为一个真正的爷们,应该做好下列小事 - ♀coolszy♂ 【厚德载物 天道酬勤】 - JavaEye技术网站
  3. CAD制图时怎么对比图纸文件的不同呢?
  4. Unity--弹力小球
  5. 时钟日历c语言源代码,日历时钟DS12887或146818的C语言源程序.doc
  6. 全国职称计算机考试取消了吗,全国职称计算机考试取消必考模块 考生自选
  7. 自考本科考暨南大学考研计算机,暨大自考本科生能考研吗?自考考研难吗?
  8. springboot使用拦截器拦截验证签名sign
  9. Ubuntu 12.04 安装 skype
  10. 化妆品电商网站响应式模板