PyQt弹出式抽屉窗口

news2024/11/13 7:53:16

代码

from enum import Enum
import sys
from PyQt5.Qt import *

class PopupOrientation(Enum):
    LEFT = 0
    TOP = 1
    RIGHT = 2
    BOTTOM = 3


class PopupMaskDialogBase(QDialog):
    """
    带有蒙版的对话框基类
    """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.__orientation = PopupOrientation.LEFT
        self.posAnimationIn: QPropertyAnimation = None
        self.posAnimationOut: QPropertyAnimation = None
        self.__stretch = 0.3
        self._hBoxLayout = QHBoxLayout(self)
        self.windowMask = QWidget(self)

        # 对话框位于蒙版的中心,所有小部件都以它为父
        self.widget = QFrame(self)
        self.widget.setObjectName('centerWidget')
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setGeometry(0, 0, parent.width(), parent.height())

        c = 0 if isDarkTheme() else 255
        self.windowMask.resize(self.size())
        self.windowMask.setStyleSheet(f'background:rgba({c}, {c}, {c}, 0.6)')
        self._hBoxLayout.addWidget(self.widget)
        self.setShadowEffect()

        parent.installEventFilter(self)

    def setStretch(self, stretch: float):
        """
        设置蒙版的拉伸比例
        :param stretch:
        :return:
        """
        if not 0.01 < stretch < 1:
            raise ValueError('stretch must be between 0.01 and 1')
        self.__stretch = stretch
        self.__initWidgetSize()

    def stretch(self) -> float:
        """
        获取蒙版的拉伸比例
        :return:
        """
        return self.__stretch

    def setShadowEffect(self, blurRadius=60, offset=(0, 10), color=QColor(0, 0, 0, 100)):
        """ add shadow to dialog """
        shadowEffect = QGraphicsDropShadowEffect(self.widget)
        shadowEffect.setBlurRadius(blurRadius)
        shadowEffect.setOffset(*offset)
        shadowEffect.setColor(color)
        self.widget.setGraphicsEffect(None)
        self.widget.setGraphicsEffect(shadowEffect)

    def setMaskColor(self, color: QColor):
        """ set the color of mask """
        self.windowMask.setStyleSheet(f"""
            background: rgba({color.red()}, {color.blue()}, {color.green()}, {color.alpha()})
        """)

    def setOrientation(self, orientation: PopupOrientation):
        """
        设置抽屉的方向
        :param orientation:
        :return:
        """
        self.__orientation = orientation
        self.__initWidgetSize()

    def __initWidgetSize(self):
        match self.orientation():
            case PopupOrientation.LEFT:
                self.widget.setFixedSize(int(self.width() * self.stretch()), self.height())
                self._hBoxLayout.setAlignment(Qt.AlignmentFlag.AlignLeft)
            case PopupOrientation.TOP:
                self.widget.setFixedSize(self.width(), int(self.height() * self.stretch()))
                self._hBoxLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
            case PopupOrientation.RIGHT:
                self.widget.setFixedSize(int(self.width() * self.stretch()), self.height())
                self._hBoxLayout.setAlignment(Qt.AlignmentFlag.AlignRight)
            case PopupOrientation.BOTTOM:
                self.widget.setFixedSize(self.width(), int(self.height() * self.stretch()))
                self._hBoxLayout.setAlignment(Qt.AlignmentFlag.AlignBottom)

    def orientation(self) -> PopupOrientation:
        """
        获取抽屉的方向
        :return:
        """
        return self.__orientation

    def showEvent(self, e):
        """ fade in """
        self.posAnimationIn = QPropertyAnimation(self, b'pos', self)
        match self.orientation():
            case PopupOrientation.LEFT:
                self.posAnimationIn.setStartValue(QPoint(-self.parent().width(), 0))
                self.posAnimationIn.setEndValue(QPoint(0, 0))
            case PopupOrientation.TOP:
                self.posAnimationIn.setStartValue(QPoint(0, -self.parent().height()))
                self.posAnimationIn.setEndValue(QPoint(0, 0))
            case PopupOrientation.RIGHT:
                self.posAnimationIn.setStartValue(QPoint(self.parent().width(), 0))
                self.posAnimationIn.setEndValue(QPoint(0, 0))
            case PopupOrientation.BOTTOM:
                self.posAnimationIn.setStartValue(QPoint(0, self.parent().height()))
                self.posAnimationIn.setEndValue(QPoint(0, 0))
        self.posAnimationIn.setDuration(200)
        self.posAnimationIn.setEasingCurve(QEasingCurve.OutCubic)
        self.posAnimationIn.start()
        super().showEvent(e)

    def done(self, code):
        """ fade out """
        self.fadeOut(code)

    def fadeOut(self, code):
        if self.posAnimationIn:
            self.posAnimationIn.stop()
            self.posAnimationIn.deleteLater()
            self.posAnimationIn = None
        self.posAnimationOut = QPropertyAnimation(self, b'pos', self)
        self.posAnimationOut.setStartValue(QPoint(0, 0))
        match self.orientation():
            case PopupOrientation.LEFT:
                self.posAnimationOut.setEndValue(QPoint(-self.parent().width(), 0))
            case PopupOrientation.TOP:
                self.posAnimationOut.setEndValue(QPoint(0, -self.parent().height()))
            case PopupOrientation.RIGHT:
                self.posAnimationOut.setEndValue(QPoint(self.parent().width(), 0))
            case PopupOrientation.BOTTOM:
                self.posAnimationOut.setEndValue(QPoint(0, self.parent().height()))
        self.posAnimationOut.finished.connect(lambda: QDialog.done(self, code))
        self.posAnimationOut.start()

    def resizeEvent(self, e: QResizeEvent):
        self.windowMask.resize(self.size())
        super().resizeEvent(e)

    def eventFilter(self, obj, e: QEvent):
        if obj is self.parent():
            if e.type() == QEvent.Resize:
                re = QResizeEvent(e)
                self.resize(re.size())

        return super().eventFilter(obj, e)

    def mousePressEvent(self, e: QMouseEvent):
        pos = e.pos()
        if self.childAt(pos) == self.windowMask:
            self.fadeOut(0)
        super().mousePressEvent(e)
 
 class DrawerMaskDialog(PopupMaskDialogBase):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.vBox = QVBoxLayout(self.widget)
        self.vBox.setAlignment(Qt.AlignTop)
        self.setStretch(0.5)

        self.vBox.addWidget(QLabel("Drawer Mask Dialog"))
        self.vBox.addWidget(QLabel("This is a drawer mask dialog."))
        self.vBox.addWidget(QLabel("You can customize the mask shape and orientation."))
        self.vBox.addWidget(QLabel("You can also add your own widgets."))
        self.vBox.addWidget(QLabel("Here is a label."))
        self.vBox.addWidget(QLabel("Here is a button."))

        self.vBox.addWidget(QLineEdit(self))
        self.vBox.addWidget(QPushButton("OK", self))
        self.vBox.addWidget(QPushButton("Cancel", self))


class Window(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.gridLayout = QGridLayout(self)
        left_button = QPushButton("Open Left Drawer", self)
        right_button = QPushButton("Open Right Drawer", self)
        top_button = QPushButton("Open Top Drawer", self)
        bottom_button = QPushButton("Open Bottom Drawer", self)

        self.gridLayout.addWidget(left_button, 1, 0)
        self.gridLayout.addWidget(right_button, 1, 2)
        self.gridLayout.addWidget(top_button, 0, 1)
        self.gridLayout.addWidget(bottom_button, 2, 1)

        left_button.clicked.connect(self.open_left_drawer)
        right_button.clicked.connect(self.open_right_drawer)
        top_button.clicked.connect(self.open_top_drawer)
        bottom_button.clicked.connect(self.open_bottom_drawer)

    def open_left_drawer(self):
        dialog = DrawerMaskDialog(self)
        dialog.setOrientation(PopupOrientation.LEFT)
        dialog.exec_()

    def open_right_drawer(self):
        dialog = DrawerMaskDialog(self)
        dialog.setOrientation(PopupOrientation.RIGHT)
        dialog.exec_()

    def open_top_drawer(self):
        dialog = DrawerMaskDialog(self)
        dialog.setOrientation(PopupOrientation.TOP)
        dialog.exec_()

    def open_bottom_drawer(self):
        dialog = DrawerMaskDialog(self)
        dialog.setOrientation(PopupOrientation.BOTTOM)
        dialog.exec_()


if __name__ == '__main__':
    QApplication.setHighDpiScaleFactorRoundingPolicy(
        Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)
    demo = Window()
    demo.resize(800, 600)
    demo.show()
    sys.exit(app.exec_())

演示

请添加图片描述

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

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

相关文章

FedProto:跨异构客户端的联邦原型学习(论文阅读)

题目&#xff1a;FedProto: Federated Prototype Learning across Heterogeneous Clients 网址&#xff1a;http://arxiv.org/abs/2105.00243 摘要 在联邦学习(FL)中&#xff0c;当客户端知识在梯度空间中聚集时&#xff0c;客户端间的异构性通常会影响优化的收敛和泛化性能。…

携手AI人才 共赢智算未来丨誉天人工智能AI大模型首期班火热报名中

在数字化浪潮汹涌澎湃的今天&#xff0c;人工智能已成为推动社会进步与产业升级的关键力量。 回顾人工智能历史&#xff0c;自1956年诞生以来&#xff0c;历经三次发展热潮和两次低谷期。五十年代符号主义和逻辑推理的出现标志着人工智能的诞生&#xff0c;引发第一次发展浪潮&…

自动驾驶AVM环视算法–全景和标定全功能算法实现和exe测试demo

参考&#xff1a;全景和标定全功能算法实现和exe测试demo-金书世界 1、测试环境 opencv310vs2022 2、使用的编程语言 c和c 3、测试的demo的获取 更新&#xff1a;测试的exe程序&#xff0c;无需解压码就可以体验算法测试效果 百度网盘&#xff1a; 链接&#xff1a;http…

开发一个自己的chrom插件

开发一个自己的chrom插件 一、创建一个文件夹 二、配置文件manifest.json 创建名字为&#xff1a;manifest.json的配置文件&#xff0c;模板如下&#xff1a; {"manifest_version": 3,"name": "Hello World Extension","version": …

Go 语言 UUID 库 google/uuid 源码解析:UUID version7 的实现

google/uuid 库地址 建议阅读内容 在阅读此篇文章之前&#xff0c;建议先了解 UUIDv1 的构成、UUIDv4 的 API 以及掌握位运算。 了解 UUIDv1 的构成可以参考Go 语言 UUID 库 google/uuid 源码解析&#xff1a;UUID version1 的实现 或 RFC 9562。 了解 UUIDv4 的 API 可以看…

【数据结构】非线性表----树详解

树是一种非线性结构&#xff0c;它是由**n&#xff08;n>0&#xff09;**个有限结点组成一个具有层次关系的集合。具有层次关系则说明它的结构不再是线性表那样一对一&#xff0c;而是一对多的关系&#xff1b;随着层数的增加&#xff0c;每一层的元素个数也在不断变化&…

算法——双指针(day3)

611.有效三角形的个数 611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 三角形的判定很简单&#xff0c;任意两边之和大于第三边即可。按照正常情况&#xff0c;我们得判断3次才可以确认是否构成三角形。 因为c在本来就是最大的情况下与…

安全测试必学神器 --BurpSuite 安装及使用实操

BurpSuite是一款功能强大的集成化安全测试工具&#xff0c;专门用于攻击和测试Web应用程序的安全性。适合安全测试、渗透测试和开发人员使用。本篇文章基于BurpSuite安装及常用实操做详解&#xff0c;如果你是一名安全测试初学者&#xff0c;会大有收获&#xff01; 一、BurpS…

C++ Qt 登录界面 Login

效果: 核心代码: #include "simpleapp.h" #include "ui_simpleapp.h" #include <QMessageBox>SimpleApp::SimpleApp(QWidget *parent): QMainWindow(parent), ui(new Ui::SimpleApp) {ui->setupUi(this); }SimpleApp::~SimpleApp() {delete ui; …

ROS、pix4、gazebo、qgc仿真ubuntu20.04

一、ubuntu、ros安装教程比较多&#xff0c;此文章不做详细讲解。该文章基于ubuntu20.04系统。 pix4参考地址&#xff1a;https://docs.px4.io/main/zh/index.html 二、安装pix4 1. git clone https://github.com/PX4/PX4-Autopilot.git --recursive 2. bash ./PX4-Autopilot…

MQTT服务端EMQX开源版安装和客户端MQTTX介绍

一、EMQX是什么 EMQX 是一款开源的大规模分布式 MQTT 消息服务器&#xff0c;功能丰富&#xff0c;专为物联网和实时通信应用而设计。EMQX 5.0 单集群支持 MQTT 并发连接数高达 1 亿条&#xff0c;单服务器的传输与处理吞吐量可达每秒百万级 MQTT 消息&#xff0c;同时保证毫秒…

C语言函数:编程世界的魔法钥匙(2)

引言 注&#xff1a;由于这部分内容比较抽象&#xff0c;而小编我又是一个刚刚进入编程世界的计算机小白&#xff0c;所以我的介绍可能会有点让人啼笑皆非。希望大家多多包涵&#xff01;万分感谢&#xff01;待到小编我学有所成&#xff0c;一定会把这块知识点重新介绍一遍&a…

Django前后端打通

跨域问题 【 0 】前言 ​ ​ 同源策略&#xff08;Same Origin Policy&#xff09;是浏览器安全策略的重要组成部分&#xff0c;它限制了来自不同源的网页之间的数据交互&#xff0c;以防止恶意攻击。当一个网页尝试执行与它的源&#xff08;即协议、域名和端口&#xff09…

Re:从零开始的C++世界——类和对象(下)

文章目录 前言1.再谈构造函数&#x1f34e;构造函数体赋值&#x1f34e;初始化列表&#x1f34e;特性&#x1f34c;特性一&#x1f34c;特性二&#x1f34c;特性三&#x1f34c;特性四&#x1f34c;特性五 &#x1f34e;explicit 关键字 2.static成员&#x1f34e;概念&#x1…

node.js动漫论坛-计算机毕业设计源码09947

摘 要 随着移动互联网的飞速发展&#xff0c;智能手机和移动互联网已经成为人们日常生活中不可或缺的一部分。在这样的背景下&#xff0c;微信小程序应运而生&#xff0c;凭借其无需下载安装、即用即走的特点&#xff0c;迅速成为连接用户与服务的桥梁。动漫作为一种深受年轻人…

《0基础》学习Python——第十六讲 __文件读写

<文件读写> 一、什么是文件读写 文件读写是指在Python程序中对文件进行读取和写入操作。通过文件读写&#xff0c;可以读取文件中的数据&#xff0c;或者向文件中写入数据。 Python提供了多种文件读写的方式&#xff0c;其中最常用的方式是使用open()函数打开一个文件&a…

ssrf复习(及ctfshow351-360)

1. SSRF 概述 服务器会根据用户提交的URL发送一个HTTP请求。使用用户指定的URL&#xff0c;Web应用可以获取图片或者文件资源等。典型的例子是百度识图功能。 如果没有对用户提交URL和远端服务器所返回的信息做合适的验证或过滤&#xff0c;就有可能存在“请求伪造"的缺陷…

huawei USG6001v1学习---信息安全概念

目录 1.什么是分布式&#xff1f; 2.什么是云计算&#xff1f; 3.APT攻击 4.安全风险能见度不足 5.常见的一些攻击 6.交换机转发原理&#xff1f; 7.各层攻击类型 7.1链路层&#xff1a; 7.2网络层&#xff1a; 7.3传输层&#xff1a; 7.4应用层&#xff1a; 1.什么…

mybatis plus json 格式转换踩坑记录

项目中有个字段存的是json数据。 我对应的实体类用的 fastjson2 中的 JsonObject 对象。 实体类&#xff1a; Data Accessors(chain true) TableName(value "plugin_template", autoResultMap true) public class PluginTemplateDo {TableId(type IdType.AUTO)p…

Mybatis<collection>实现一对多

时隔多年又用到这样的查询方式了,提前声明一下分页最后返回的数据会小于每页条数&#xff0c;废话不多说直接上代码&#xff01; Data public class PbcUserTargetTaskPageVO {ApiModelProperty("个人绩效指标id")private Long id;ApiModelProperty("月份"…