python3GUI--Joy音乐播放器 在线播放器 播放器 By:PyQt5(附下载地址)
文章目录
- 一.前言
- 二.项目简介
- 三.详细模块介绍
- 1.主界面
- 2.歌单广场
- 3.歌单详情页
- 4.歌手筛选
- 5.歌手详情页
- 6.专辑详情页
- 7.歌曲榜单页
- 8.搜索结果页
- 9.其他
- 1.托盘菜单
- 2.设置
- 四.核心问题回答
- 1.软件UI效果实现
- 2.为什么我做不出来这么漂亮的界面?
- 3.旋转黑胶效果怎么做出来的呀?
- 4.关于项目
- 1.项目结构
- 2.项目依赖
- 3.项目打包
- 五.总结
[更新于20250822],文件大小76.7 M,欢迎下载体验!点击下载
本次采用混合开发制作了一款高颜值的在线音乐播放器,内置多个功能页面,非常适合学习!
拿到代码的同学,请务必仔细阅读本篇博客,避免踩坑!
本篇能帮您解决大量学习pyqt5过程中的问题,少走弯路!
一.前言
本次开发的音乐播放器项目名称为:pyqt5-joy-music,这是一款使用混合语言开发的高颜值在线音乐播放器,博主参考了一款VUE风格的音乐播放器,使用html+pyqt5完成整个项目的开发!
二.项目简介
博主使用一张思维导图展示所有功能,大家可以自行放大查看。
三.详细模块介绍
1.主界面
主界面由顶部窗口控制、基本信息展示,中间为内容展示区、歌曲信息展示区域,底部为播放控制区域。
我们为了放置背景过度拉伸导致原图失真,本次采用了svg图像作为背景图片,设计了多种(十款)纯色、渐变色、纹理方案。
我们的播放器启动后会自动加载上次播放的内容到播放列表,如果没有播放历史,则加载推荐歌曲到播放列表,用户可以通过双击歌曲名称的方式开始播放歌曲,音乐播放前会加载歌曲基本信息和歌词数据到右侧信息展示区域,我们采用动态的live标志和旋转的专辑黑胶转盘来标识当前在播音乐。
用户可以将鼠标移动到歌曲上,会通过toolTip展示歌曲的详细信息,用户在歌曲上右击鼠标,会展示详细的歌曲操作菜单:播放歌曲、下载歌曲、播放列表操作:清空列表、移除当前,搜索相关:搜索歌曲名称、搜索专辑、搜索歌手。
2.歌单广场
这是主界面内容的另一个界面,主要是通过鼠标滚动在界面中筛选歌单,歌单内容展示逻辑为无限下拉,用户可以在左侧改变歌单排序规则,可选项为:最新、最热。
3.歌单详情页
用户可以点击歌单封面上的播放按钮开始播放歌单内容,点击歌单名称进入歌单详情页。
在这个页面用户能够查看所选歌单的详细信息,页面内容包含基本信息展示以及歌曲列表,歌曲列表一页展示30条,基本信息和歌曲列表是同步向下滚动的。
点击播放按钮,软件开始从第一首歌曲开始播放,双击歌曲列表的歌曲,软件从用户选择的歌曲开始播放,并且用播放列表替换正在播放
4.歌手筛选
在这个页面用户可以通过不同的条件对歌手进行筛选,我们内置了多个筛选条件,用户可以采用极细的粒度进行筛选,筛选结果里的歌手支持无限下拉加载的,当下拉一定高度的时候,右下角会展示“回到顶部”的按钮,用户可以快速回到顶部更改筛选项。
5.歌手详情页
我们为每位歌手设计了漂亮的歌手详情页,在这个页面用户能看到歌手的信息以及相关数据(单曲、专辑、相似歌手推荐以及用户的详细文字信息),用户可以通过切换tab来查看不同维度的展示信息。
用户可以点击歌手基本信息下方的播放按钮播放用户歌曲、点击分享按钮会复制分享信息到用户剪切板,用户可以复制信息发给自己的好友!
用户可以双击歌曲,软件就会开始播放所选的指定歌曲
用户可以点击专辑封面开始播放所选专辑歌曲,点击专辑名称进入专辑详情页面
用户点击推荐的相似歌手封面播放按钮,就开始播放选择的歌手的歌曲,点击相似歌手的名字,到所选歌手的二级页
用户点击详细信息tab,可以查看当前歌手的详细文字信息
6.专辑详情页
您可以通过点击专辑名字到专辑的二级页,即专辑详情页,在这个页面可以查看所选专辑的详细信息以及歌曲数据,表格内歌曲数据是通过热度降序排序,点击播放按钮,就开始从专辑第一首歌曲开始播放,点击分享按钮能够分享专辑并复制分享文案到剪切板。
7.歌曲榜单页
在这个页面展示了不同类别的歌曲榜单,用户可以点击榜单封面的播放按钮从第一首开始播放所选榜单的歌曲。
8.搜索结果页
用户在上方选择“歌曲搜索”,点击后打开搜索子窗口,您可以通过输入关键字后点击搜索按钮(或者按下回车)对歌曲进行搜索,最后软件跳转到搜索结果页展示歌曲的搜索结果。
9.其他
1.托盘菜单
我们的音乐播放器拥有和主流样式一致的托盘菜单组件,软件启动后会自动注册托盘菜单到屏幕右下角(windows),用户可以将鼠标移入托盘菜单查看当前在播歌曲,亦可通过按下鼠标右键查看托盘菜单的详细内容并操作音乐播放器,可以操作的内容包括:播放控制(上一曲、播放暂停、下一曲)、音量控制(静音、详细音量调节)、播放模式切换(单曲循环、随机播放、列表循环)、打开设置以及退出软件,这里值得一提的是当歌曲正在播放时,播放控制和音量调节之间展示了歌曲的名称和歌手名,当这个信息超过了一定的宽度时,这段文字将会左右滚动,尽可能将全部的信息展示出来!
2.设置
我们的音乐播放器支持多种内容设置,并且能够保存设置到本地配置文件,方便再次启动后配置生效,具体的设置内容为:
开关类:
精简tab模式:开启此功能,界面只会展示“正在播放”和“歌曲搜索”
系统不休眠:开启此功能,我们的电脑屏幕不会息屏,方便要听歌但是又不操作屏幕的用户
传送门:这是作者的一个巧思,用户可以在这里选择要传送到的页面,可以选择歌单、歌手、专辑
重置背景:将软件背景还原到默认的背景图
清空缓存:我们采用了cache的方式缓存了一些图片数据,目的是加速音乐播放(主要是图片),清空之后会减少本地磁盘占用,但是下次播放音乐会重新加载图片
关于作者:点击之后会弹出询问对话框,用户选择了Yes之后打开博主的CSDN博客
关于软件:点击之后会弹出一段文案,告知用户本软件相关信息
更换背景:我们使用分割线将开关和背景选择区域分割开来,在下方设有垂直滚动区域,里面罗列了几种不同颜色、纹理风格的背景图,用户通过点击对应的背景图来改变背景效果,设置是实时生效的
这个页面的所有对话框都是有二次确认的,每个弹出的对话框都是同样的风格,窗口弹出时,背景效果为高斯模糊效果。
四.核心问题回答
1.软件UI效果实现
经常会有朋友私聊我,和博主询问.ui文件,这里统一回答:没有UI文件,软件上的所有pyqt组件都是手搓的自定义组件,本次软件的一些位置采用了html语言,这样可以更加高度自定义展示内容,让我们的软件整体软件更加高颜值!
我们使用pyqt5+html+不依赖外部html文件的方式渲染展示组件,使用QWebChannel进行js和python之间的数据交互,实现了数据和组件的双向绑定。
我们定义了NoContextMenuWebEngineView组件,能够帮我们阻塞页面的右击菜单,采用NoRightClickWebEnginePage阻塞掉所有右击事件,更能让我们隐藏html浏览器效果,实现了“以html元素替代QWidget组件”。
2.为什么我做不出来这么漂亮的界面?
这里我想说:一个好看实用的作品一定是有参考的,当然也包括作者的奇思妙想,这里博主参考了VUE版本的音乐播放器样式(https://blog.hzyo.cn/music/),这位博主做的界面相当漂亮,给人一种很干净清爽的感觉,唯一觉得不足的地方是页面太少了,为此,博主在现有基础上进行开发、完善,加入了多个页面以及子页面,真正实现了一个高颜值且实用的音乐播放器,最后再次感谢!
3.旋转黑胶效果怎么做出来的呀?
这个组件采用重写QLabel的paintEvent函数实现黑胶、唱片针的展示,采用圆形效果展示专辑封面,值得一提的是,我们采用了缓存的方式加载歌曲专辑封面,也就是说,越是播放过的歌曲,加载封面越快,二次加载相当于读取本地文件,无网络访问请求,就是因为用了这些缓存的思想,加速了软件的速度。
下面是黑胶转盘组件的源代码:
class AlbumWidget(QLabel):"""更像唱片的旋转 QLabel"""def __init__(self, parent=None):super().__init__(parent)self.param_init()self.timer_init()self.ui_init()def param_init(self):self._angle = 0self.label_width = 170self.extra = 20 # 额外的宽高self._pix = QPixmap()self.side_ratio = 0.65 # 专辑封面面积占比self.default_cover = style_conf.default_album_coverself.light_circle_color = QColor(255, 255, 255) # 黑胶外圈颜色self.center_dot_color = QColor(220, 220, 220) # 中心点颜色self.setAttribute(Qt.WA_TranslucentBackground)def ui_init(self):self.setFixedSize(self.label_width + self.extra, self.label_width + self.extra)self.set_album_pic(self.default_cover)def timer_init(self):self.rotate_timer = QTimer(self)self.rotate_timer.timeout.connect(self.rotate)self.rotate_timer.setInterval(system_conf.album_rotate_timer_interval)def set_album_pic(self, album_pic):"""设置专辑封面图片:param album_pic::return:"""def set_pic(pix):if not pix:returnelif not isinstance(pix, QPixmap):pix = QPixmap(pix)self._pix = pix.scaled(int(self.label_width * self.side_ratio),int(self.label_width * self.side_ratio),Qt.KeepAspectRatio, Qt.SmoothTransformation)self._pix = rounded_pixmap(self._pix, int(self._pix.width() / 2))self.update()self.control_rotate_state(True)if not album_pic:returnif album_pic.startswith(":"): # 本地资源set_pic(album_pic)else: # 网络图self.thread = subThread(subThread.get_web_pix, album_pic, byte_data=True)self.thread.pixmap_finished.connect(lambda pix: set_pic(pix))self.thread.start()self._angle = 0def control_rotate_state(self, state):"""设置旋转状态:param state::return:"""if state:if not self.rotate_timer.isActive():self.rotate_timer.start()else:if self.rotate_timer.isActive():self.rotate_timer.stop()def rotate(self):"""专辑封面旋转:return:"""self._angle = (self._angle + 1) % 360self.update()def paintEvent(self, event):painter = QPainter(self)painter.setRenderHint(QPainter.Antialiasing)painter.setRenderHint(QPainter.SmoothPixmapTransform)center = QPointF(self.width() / 2, self.height() / 2)radius = self.label_width / 2# 0. 绘制白色发光外圈glow_radius = radius + 10 # 比唱片略大gradient = QRadialGradient(center, glow_radius)glow_radius = radius + 35 # 发光范围更大color = self.light_circle_colorgradient.setColorAt(0.0, QColor(color.red(), color.green(), color.blue(), 180))gradient.setColorAt(0.6, QColor(color.red(), color.green(), color.blue(), 80))gradient.setColorAt(1.0, QColor(color.red(), color.green(), color.blue(), 0))painter.setBrush(gradient)painter.setPen(Qt.NoPen)painter.drawEllipse(center, glow_radius, glow_radius)# 1. 绘制黑胶外圈painter.setBrush(QColor(30, 30, 30))painter.setPen(Qt.NoPen)painter.drawEllipse(center, radius, radius)# 1.1 绘制灰色磁道(只在外圈区域)painter.save()painter.translate(center)track_pen = QPen(QColor(80, 80, 80)) # 灰色磁道track_pen.setWidth(1)painter.setPen(track_pen)track_count = 15 # 磁道条数inner_radius = radius * 0.7 # 磁道起始半径,避免覆盖中间封面for i in range(track_count):r = inner_radius + (radius - inner_radius) * (i / track_count)painter.drawEllipse(QPointF(0, 0), r, r)painter.restore()# 2. 平移 + 旋转画布(用于绘制封面图)painter.translate(center)painter.rotate(self._angle)# 3. 绘制中间封面图(略小)pix_w = self._pix.width()pix_h = self._pix.height()painter.drawPixmap(-pix_w / 2, -pix_h / 2, self._pix)# 4. 恢复角度painter.rotate(-self._angle)painter.translate(-center)# 5. 绘制中心小圆点(轴心)center_dot_radius = 5painter.setBrush(self.center_dot_color)painter.setPen(Qt.NoPen)painter.drawEllipse(center, center_dot_radius, center_dot_radius)painter.end()
4.关于项目
我们的项目为私有项目,项目名称wieldpyqt5-joy-music,项目开发周期为20天,主要耗时的地方是设计样式,好在问题都解决了。
1.项目结构
下图为项目代码结构,整体代码量为9000行,主要代码量由unique_widgets.py产生,约6.5K,这里为主要的页面代码,包含webengine和html
main_page.py为主要的逻辑调度,所有的组件都被它调度起来,把我们整个系统串联
threads/目录是核心线程,采用多线程可以避免不必要的卡顿,加速音乐播放器软件执行效率
engine/目录是核心引擎,所有的网络内容操作都在这里进行,配合核心线程完成网络数据的获取
conf/目录是主要的配置目录,这里面包含样式、系统内容、测试数据,这里面内容的修改直接影响软件界面展示的内容
resource/目录是主要的资源所在目录,我们创建了bg_imgs/目录用于存储背景图,创建了others/目录用于存储软件图标以及其他相关图片资源内容
utils/是系统工具类和工具方法,都是博主常用的公共方法,每个方法在软件中都有引用
2.项目依赖
大家拿到源代码直接执行下面命令进行项目依赖的一键安装:
pip install -r requirements.txt
本项目依赖相当干净,博主贴在下方:
PyQt5==5.15.11
PyQt5_sip==12.15.0
QtAwesome==1.3.1
PyYAML==6.0.2
3.项目打包
关于项目打包本来笔者不抱有太大希望,因为我们采用的混合开发可能会有兼容问题,刚开始确实还有点担心,但是第一次尝试打包成功之后,博主更加坚定了这种开发方案的思路。
本次打包的安装包大小为76.7M,大家下载下来安装包,按照傻瓜式的下一步进行安装即可,最后得到和博主同款好用高颜值的音乐播放器!
五.总结
本次和大家分享了我开发的高颜值音乐播放器-Joy音乐播放器,这款播放器包含多个页面,满足了我们日常的听歌需求,在博客中和大家介绍了我进行“混合开发”的大致思路,为以后项目开发指明了方向,这套代码适合有html基础并且愿意学习pyqt技术的同学来学习,真的很值得一学!