PyQt弹出式抽屉窗口

代码

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_())

演示

请添加图片描述

相关推荐

  1. SublimeText3多次保存自动窗口

    2024-07-18 19:50:06       41 阅读
  2. react ant design 通过函数 modal窗口

    2024-07-18 19:50:06       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 19:50:06       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 19:50:06       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 19:50:06       58 阅读
  4. Python语言-面向对象

    2024-07-18 19:50:06       69 阅读

热门阅读

  1. 正则表达式

    2024-07-18 19:50:06       19 阅读
  2. 框架

    框架

    2024-07-18 19:50:06      19 阅读
  3. opencv—常用函数学习_“干货“_5

    2024-07-18 19:50:06       24 阅读
  4. 光伏储能剑指何方

    2024-07-18 19:50:06       20 阅读
  5. Web前端-Web开发CSS基础5-浮动

    2024-07-18 19:50:06       18 阅读