python3GUI--详细讲解一个QQ音乐组件的制作By:PyQt5(详细介绍、附源代码)

news2024/12/24 8:40:15

文章目录

  • 一.前言
  • 二.设计
    • 1.思路
    • 2.布局
    • 3.自定义组件
      • 1.支持hover事件的QLabel
      • 2.自定义的QToolButton
    • 4.图片圆角
    • 5.动画效果
  • 三.源代码
  • 四.总结


一.前言

有网友给我留言,问我那种可交互的音乐组件是怎么制作的,交互效果是如何实现的,本篇以QQ音乐的一个组件为例,从布局到动画,详细阐述相关组件的制作流程,实现下图效果:
请添加图片描述
看完本篇,你将会收获:

1.组件布局
2.信号与槽
3.自定义组件
4.图片圆角
5.动画效果
6.组件叠放

Let’s do it !

二.设计

1.思路

这里讲一下我们设计的主要思路:

此组件主体为垂直布局,由上方封面以及下方文字组成,其中在默认状态下,封面右下角展示歌单播放量,背景为黑色,文字为白色,当鼠标移入封面时,右下角展示的信息消失,在封面正中央展示一个播放按钮,背景颜色为黑色半透明,当鼠标移入按钮时,按钮变成绿色。

2.布局

我们使用一个QLabel作为封面图片的载体,通过调用.setPixmap()方法把图片设置到QLabel中,封面右下角的播放数据也使用一个QLabel,通过QSS的background-color改变背景颜色、border-radius设置圆角,padding等参数设置边距,再实例化一个QLabel作为鼠标移入后按钮的背景,起到一个遮罩层的效果,最后再使用一个QToolButton,通过设置它的ICON设置其图表。难点来了,如何在封面上叠放歌单数据、遮罩层背景以及按钮。这里我们实例化一个QVBoxLayout,把它的父类设置为封面QLabel,之后把需要叠放的组件加入到布局中即可,通过创建QPropertyAnimation控制布局内的组件显示与隐藏,即可实现我们所说的交互。
相关代码参考:

    def ui_init(self):
        self.layout = QVBoxLayout()
        self.cover_label = MyLabel(self)

        self.cover_label.setObjectName("cover_label")
        self.name_label = QLabel()
        self.name_label.setWordWrap(False)
        self.name_label.setCursor(Qt.PointingHandCursor)
        self.name_label.setObjectName("name_label")

        self.hover_btn_label = QLabel()
        self.hover_btn_label.setObjectName("hover_btn_label")
        self.hover_btn = Hover_mormal_button(self.hover_btn_label)
        self.hover_btn.setObjectName("hover_btn")
        self.hover_btn.setIconSize(QSize(55, 55))
        self.hover_btn.set_icon("fa.play-circle")
        self.hover_btn.setVisible(False)
        self.hover_btn_label.setVisible(False)
        top_hover_layout = QVBoxLayout(self.cover_label)

        self.hover_label = QLabel()
        self.hover_label.setObjectName("hover_label")
        self.hover_label.setFixedSize(90, 34)
        top_hover_layout.addWidget(self.hover_btn_label)
        top_hover_layout.setSpacing(0)
        top_hover_layout.setContentsMargins(0, 0, 0, 0)
        hover_layout = QVBoxLayout(self.hover_btn_label)
        hover_layout.addWidget(self.hover_btn)
        hover_layout.setAlignment(self.hover_btn, Qt.AlignCenter | Qt.AlignCenter)
        top_hover_layout.addWidget(self.hover_label)
        top_hover_layout.setAlignment(self.hover_label, Qt.AlignRight | Qt.AlignBottom)
        self.hover_label.setText("🎧34.6万")
        self.name_label.setText("抖音热歌:超好听的店铺BGM")
        self.cover_label.setPixmap(
            rounded_pixmap(QPixmap(":res/rescourses/cover.png").scaled(167, 167), radius=10))
        self.layout.addWidget(self.cover_label)
        self.layout.addWidget(self.name_label)
        self.layout.setStretch(0, 10)
        self.setLayout(self.layout)

在这里插入图片描述
在这里插入图片描述

3.自定义组件

为了代码复用,这里涉及两个自定义组件,分别实现了不同的功能,下面我来介绍一下。

1.支持hover事件的QLabel

这里重写了QLabel的enterEvent与leaveEvent事件,通过检测鼠标的移入和移出事件,将hovered信号发射出去,发射给父窗口。

class MyLabel(QLabel):
    clicked = pyqtSignal()  # 能够点击
    hovered = pyqtSignal(bool)

    def __init__(self, parent=None):
        super(MyLabel, self).__init__(parent)
        self.setParent(parent)
        self.setScaledContents(True)  # 实现缩放

    def mousePressEvent(self, ev: QtGui.QMouseEvent):
        self.clicked.emit()

    def enterEvent(self, a0: QtCore.QEvent):
        self.setCursor(Qt.PointingHandCursor)  # 改变鼠标样式
        self.hovered.emit(True)

    def leaveEvent(self, a0: QtCore.QEvent):
        self.hovered.emit(False)

2.自定义的QToolButton

这是笔者自定义的一个QToolButton,因为要设计UI统一,并且要做到代码复用,这里干脆直接封装成一个类,对外提供一个接口,可设置鼠标hover之后的图标颜色样式,默认白色,hover之后是绿色。

class Hover_mormal_button(QToolButton):
    def __init__(self, parent=None):
        super(Hover_mormal_button, self).__init__()
        self.setParent(parent)
        self.normal_color = "white"
        self.hovered_color = "#1fcf9e"
        self.icon_name = ""
        self.setCursor(Qt.PointingHandCursor)
        self.setIconSize(QSize(20, 20))

    def set_icon(self, icon_name, normal_color="", hovered_color=""):
        self.icon_name = icon_name
        if normal_color:
            self.normal_color = normal_color
        if hovered_color:
            self.hovered_color = hovered_color
        self.setIcon(QIcon(qtawesome.icon(self.icon_name, color=self.normal_color)))

    def enterEvent(self, a0: QtCore.QEvent):
        self.setIcon(QIcon(qtawesome.icon(self.icon_name, color=self.hovered_color)))
        super(Hover_mormal_button, self).enterEvent(a0)

    def leaveEvent(self, a0: QtCore.QEvent):
        self.setIcon(QIcon(qtawesome.icon(self.icon_name, color=self.normal_color)))

4.图片圆角

这里使用一个公共方法将QPixmap的边缘做圆角处理。

def rounded_pixmap(pixmap, radius):
    rounded_pixmap = QPixmap(pixmap.size())
    rounded_pixmap.fill(Qt.transparent)

    painter = QPainter(rounded_pixmap)
    painter.setRenderHint(QPainter.Antialiasing)

    path = QPainterPath()
    path.addRoundedRect(0, 0, pixmap.width(), pixmap.height(), radius, radius)

    painter.setClipPath(path)
    painter.drawPixmap(0, 0, pixmap)

    return rounded_pixmap

5.动画效果

前面说了,是通过鼠标移入移出控制封面上方信息与遮罩层按钮的隐藏与显示实现的交互,绑定的代码如下:

self.cover_label.hovered.connect(lambda s: self.control_hover_layer(s))

槽函数代码如下

    def control_hover_layer(self, s):
        """
        控制遮罩层
        :return:
        """
        self.hover_label.setVisible(not s)
        effect = QGraphicsOpacityEffect(self)
        self.hover_btn_label.setGraphicsEffect(effect)
        animation = QPropertyAnimation(self)
        animation.setTargetObject(effect)
        animation.setPropertyName(b'opacity')
        animation.setDuration(300)
        animation.setKeyValueAt(0, 0)
        animation.setKeyValueAt(1, 1)
        if s:
            animation.setDirection(QAbstractAnimation.Forward)
        else:
            animation.setDirection(QAbstractAnimation.Backward)
        animation.start(QAbstractAnimation.DeleteWhenStopped)

        self.hover_btn.setVisible(s)
        self.hover_btn_label.setVisible(s)

请添加图片描述

三.源代码

源代码如下

import sys

import qtawesome
from PyQt5.QtCore import pyqtSignal, Qt, QSize, QPropertyAnimation, QAbstractAnimation
from PyQt5.QtGui import QPixmap, QIcon, QPainter, QPainterPath
from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QToolButton, QVBoxLayout, QGraphicsOpacityEffect
from qtpy import QtCore, QtGui
import resource_rc


def rounded_pixmap(pixmap, radius):
    rounded_pixmap = QPixmap(pixmap.size())
    rounded_pixmap.fill(Qt.transparent)

    painter = QPainter(rounded_pixmap)
    painter.setRenderHint(QPainter.Antialiasing)

    path = QPainterPath()
    path.addRoundedRect(0, 0, pixmap.width(), pixmap.height(), radius, radius)

    painter.setClipPath(path)
    painter.drawPixmap(0, 0, pixmap)

    return rounded_pixmap


class Hover_mormal_button(QToolButton):
    def __init__(self, parent=None):
        super(Hover_mormal_button, self).__init__()
        self.setParent(parent)
        self.normal_color = "white"
        self.hovered_color = "#1fcf9e"
        self.icon_name = ""
        self.setCursor(Qt.PointingHandCursor)
        self.setIconSize(QSize(20, 20))

    def set_icon(self, icon_name, normal_color="", hovered_color=""):
        self.icon_name = icon_name
        if normal_color:
            self.normal_color = normal_color
        if hovered_color:
            self.hovered_color = hovered_color
        self.setIcon(QIcon(qtawesome.icon(self.icon_name, color=self.normal_color)))

    def enterEvent(self, a0: QtCore.QEvent):
        self.setIcon(QIcon(qtawesome.icon(self.icon_name, color=self.hovered_color)))
        super(Hover_mormal_button, self).enterEvent(a0)

    def leaveEvent(self, a0: QtCore.QEvent):
        self.setIcon(QIcon(qtawesome.icon(self.icon_name, color=self.normal_color)))


class MyLabel(QLabel):
    """
    帶圓角的label
    """
    clicked = pyqtSignal()  # 能够点击
    hovered = pyqtSignal(bool)

    def __init__(self, parent=None):
        super(MyLabel, self).__init__(parent)
        self.setParent(parent)
        self.setScaledContents(True)  # 实现缩放

    def mousePressEvent(self, ev: QtGui.QMouseEvent):
        self.clicked.emit()

    def enterEvent(self, a0: QtCore.QEvent):
        self.setCursor(Qt.PointingHandCursor)  # 改变鼠标样式
        self.hovered.emit(True)

    def leaveEvent(self, a0: QtCore.QEvent):
        self.hovered.emit(False)


class normalMusicWidget(QWidget):
    """
    一般音乐组件
    """
    style = """*{font-family:"微软雅黑";}#hover_label{background-color:black;color:white;border:1px solid black;border-radius:12px;padding-left:5px;margin-right:10px;margin-bottom:10px;}#name_label:hover{color:rgb(30,206,155)}#hover_btn_label{background-color:rgba(0,0,0,0.5);border:1px solid rgba(0,0,0,0.5);border-radius:10px;}#hover_btn{border:none;}"""

    def __init__(self):
        super(normalMusicWidget, self).__init__()
        self.ui_init()
        self.setStyleSheet(self.style)
        self.slot_init()

    def ui_init(self):
        self.layout = QVBoxLayout()
        self.cover_label = MyLabel(self)

        self.cover_label.setObjectName("cover_label")
        self.name_label = QLabel()
        self.name_label.setWordWrap(False)
        self.name_label.setCursor(Qt.PointingHandCursor)
        self.name_label.setObjectName("name_label")

        self.hover_btn_label = QLabel()
        self.hover_btn_label.setObjectName("hover_btn_label")
        self.hover_btn = Hover_mormal_button(self.hover_btn_label)
        self.hover_btn.setObjectName("hover_btn")
        self.hover_btn.setIconSize(QSize(55, 55))
        self.hover_btn.set_icon("fa.play-circle")
        self.hover_btn.setVisible(False)
        self.hover_btn_label.setVisible(False)
        top_hover_layout = QVBoxLayout(self.cover_label)

        self.hover_label = QLabel()
        self.hover_label.setObjectName("hover_label")
        self.hover_label.setFixedSize(90, 34)
        top_hover_layout.addWidget(self.hover_btn_label)
        top_hover_layout.setSpacing(0)
        top_hover_layout.setContentsMargins(0, 0, 0, 0)
        hover_layout = QVBoxLayout(self.hover_btn_label)
        hover_layout.addWidget(self.hover_btn)
        hover_layout.setAlignment(self.hover_btn, Qt.AlignCenter | Qt.AlignCenter)
        top_hover_layout.addWidget(self.hover_label)
        top_hover_layout.setAlignment(self.hover_label, Qt.AlignRight | Qt.AlignBottom)
        self.hover_label.setText("🎧34.6万")
        self.name_label.setText("抖音热歌:超好听的店铺BGM")
        self.cover_label.setPixmap(
            rounded_pixmap(QPixmap(":res/rescourses/cover.png").scaled(167, 167), radius=10))
        self.layout.addWidget(self.cover_label)
        self.layout.addWidget(self.name_label)
        self.layout.setStretch(0, 10)
        self.setLayout(self.layout)

    def slot_init(self):
        self.cover_label.hovered.connect(lambda s: self.control_hover_layer(s))

    def control_hover_layer(self, s):
        """
        控制遮罩层
        :return:
        """
        self.hover_label.setVisible(not s)
        effect = QGraphicsOpacityEffect(self)
        self.hover_btn_label.setGraphicsEffect(effect)
        animation = QPropertyAnimation(self)
        animation.setTargetObject(effect)
        animation.setPropertyName(b'opacity')
        animation.setDuration(300)
        animation.setKeyValueAt(0, 0)
        animation.setKeyValueAt(1, 1)
        if s:
            animation.setDirection(QAbstractAnimation.Forward)
        else:
            animation.setDirection(QAbstractAnimation.Backward)
        animation.start(QAbstractAnimation.DeleteWhenStopped)

        self.hover_btn.setVisible(s)
        self.hover_btn_label.setVisible(s)


if __name__ == '__main__':
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)  # 高分辨率浏览器自适应
    app = QApplication(sys.argv)
    win = normalMusicWidget()
    win.show()
    sys.exit(app.exec_())

四.总结

本次详细讲解一个QQ音乐组件的制作,附上了源代码,UI设计流程大家可自行体会,只要慢慢拆解就没有难的布局,重点在实现思路。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1036362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据-玩转数据-Flink SQL编程

一、概念 1.1 Apache Flink 两种关系型 API Apache Flink 有两种关系型 API 来做流批统一处理:Table API 和 SQL。 Table API 是用于 Scala 和 Java 语言的查询API,它可以用一种非常直观的方式来组合使用选取、过滤、join 等关系型算子。 Flink SQL 是…

大转盘抽奖活动设计完全指南,轻松打造难忘的客户体验

大转盘抽奖活动是一种非常受欢迎的营销方式,可以吸引消费者参与并增加品牌曝光度。下面将为大家介绍一种简单易学的大转盘抽奖活动制作教程。 首先,我们需要使用第三方平台/工具来制作大转盘抽奖活动。这里以乔拓云平台为例,首先我们需要注册…

基于监督学习的多模态MRI脑肿瘤分割,使用来自超体素的纹理特征(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

1小时掌握Python操作Mysql数据库之pymysql模块技术

大家好,我是python222小锋老师。前段时间卷了一套 Python3零基础7天入门实战 近日锋哥又卷了一波课程,Python操作Mysql数据库的pymysql技术,文字版视频版。1小时掌握。 视频版教程 1小时掌握Python操作Mysql数据库之pymysql模块技术 文字版…

Remix 2.0 正式发布,现代化全栈Web框架!

9 月 16 日,全栈 Web 框架 Remix 正式发布了 2.0 版本,Remix 团队在发布 1.0 版本后经过近 2 年的持续努力,发布了 19 个次要版本、100 多个补丁版本,并解决了数千个问题和拉取请求,终于迎来了第二个主要版本&#xff…

【计算机毕业设计】基于SpringBoot+Vue记帐理财系统的设计与实现

博主主页:一季春秋博主简介:专注Java技术领域和毕业设计项目实战、Java、微信小程序、安卓等技术开发,远程调试部署、代码讲解、文档指导、ppt制作等技术指导。主要内容:毕业设计(Java项目、小程序、安卓等)、简历模板、学习资料、…

【红外图像增强】基于引力和侧向抑制网络的红外图像增强模型(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

【Verilog教程】4.3Verilog 时序控制

关键词:时延控制,事件触发,边沿触发,电平触发 Verilog 提供了 2 大类时序控制方法:时延控制和事件控制。事件控制主要分为边沿触发事件控制与电平敏感事件控制。 时延控制 基于时延的时序控制出现在表达式中&#xff…

【ACDC数据集】:预处理ACDC心脏3D MRI影像数据集到VOC数据集格式,nii转为jpg,label转为png

【Segment Anything Model】做分割的专栏链接,欢迎来学习。 【博主微信】cvxiaoyixiao 本专栏为公开数据集的预处理,持续更新中。 文章目录 1️⃣ ACDC数据集介绍2️⃣ ACDC数据集样例 3️⃣ 预处理ACDC目标 4️⃣ 处理结果样图 5️⃣ 代码 6️⃣ 划分测…

【算法挨揍日记】day08——30. 串联所有单词的子串、76. 最小覆盖子串

30. 串联所有单词的子串 30. 串联所有单词的子串 题目描述: 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如,如果 words ["…

SSM - Springboot - MyBatis-Plus 全栈体系(十一)

第二章 SpringFramework 五、Spring AOP 面向切面编程 6. Spring AOP 基于 XML 方式实现(了解) 6.1 准备工作 加入依赖和基于注解的 AOP 时一样。准备代码把测试基于注解功能时的 Java 类复制到新 module 中,去除所有注解。 6.2 配置 Sp…

SpringBoot项目(百度AI整合)——如何在Springboot中使用语音文件识别 ffmpeg的安装和使用

前言 前言:在实际使用中,经常要参考官方的案例,但有时候因为工具的不一样,比如idea 和 eclipse,普通项目和spring项目等的差别;还有时候因为水平有限,难以在散布于官方的各个文档读懂&#xff…

【广州华锐互动】VR虚拟党建云展馆:带你沉浸式领略红色文化

在新时代的背景下,科技与党建的结合已成为一种趋势。VR(Virtual Reality,虚拟现实)技术作为一种新兴的科技手段,为党建工作提供了全新的载体。VR虚拟党建云展馆,就是将VR技术应用于党建工作的一个典型例子&…

招聘程序员(软件开发工程师),如何做岗位胜任力测评?

一、 程序员的基本工作内容 1、 负责项目组内的代码维护和更新迭代,保证研发效率,对于运营产品提出的需求应积极沟通并实现。 2、 规范相关开发文档等相关资料,对于有变更的代码和功能需求,要对开发文档做出相应的变更。 3、 作为…

三维重建_纹理重建与表面细化

目录 前言:为什么要重建纹理? 1. 纹理图像的自动创建 1.1 基础知识 1.2 算法流程 1.2.1 视角选择 1.2.2 纹理坐标的计算 1.2.3 全局颜色调整 1.2.4 泊松图像编辑 1.2.5 OBJ文件 1.3 结果示例 2. 网格细化优化 2.1 基础知识与数学模型 2.2 优…

【Python基础】对Python的深入认识以及各种情况的报错汇总

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

在给应用ASO优化时要注意些什么

应用名称是搜索引擎优化和转化率优化非常重要的元素。用户在搜索结果页面中看到我们的应用程序,这是他们决定是否想要更多地了解我们应用的地方。当用户已经在查看产品页面时,应用程序名称也会影响转化率,如果列表元数据有吸引力,…

Django的设计模式及模板层

Django的设计模式及模板层 设计模式MVC和MVT MVC 代表 Model-View-Controller(模型-视图-控制器)模式。 M 模型层(Model),主要用于对数据库层的封装 V 视图层(View),用于向用户展示结果 (WHAT HOW) C 控制(Controller,用于处理请求、获取数据、返回结果(重要) 作…

【数据集标注】上古软件LabelImg的保姆级使用教程

1:下载文件并解压 进入链接:mirrors / tzutalin / labelimg GitCode 点击绿色按钮【克隆】 ,再点击按钮【zip】,随后下载到本地 移动下载的压缩文件到合适的位置,此处我以桌面为例子 右键点击该zip压缩文件&#xff…

WINDOWS 7-11 磁盘分区教程

前言: 现在很多新电脑,尤其是用固态硬盘的电脑,往往内存不是很大,默认系统就给1个c盘(系统)或者再加一个D盘(软件盘)。为了更好的管理自己电脑的文件,我们需要增加一个或…