多媒体(Multimedia)是多种媒体的综合,一般包括文本,声音和图像等多种媒体形式。
在计算机系统中,多媒体指组合两种或两种以上媒体的一种人机交互式信息交流和传播媒体。
使用的媒体包括文字、图片、照片、声音、动画和影片,以及程式所提供的互动功能。
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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @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。中间的
“-”是英文字符的短横杠,这样的目的是能够将歌曲名称和歌手分开显示到界面上。