代码
import sys
from enum import Enum
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._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 = 255
self.windowMask.resize(self.size())
self.windowMask.setStyleSheet(f'background:rgba({c}, {c}, {c}, 0.6)')
self._hBoxLayout.setSpacing(0)
self._hBoxLayout.setContentsMargins(0, 0, 0, 0)
self._hBoxLayout.addWidget(self.widget)
self.parent().installEventFilter(self)
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 setViewContentsMargins(self, left, top, right, bottom):
self._hBoxLayout.setContentsMargins(left, top, right, bottom)
def setAlignment(self, alignment):
self._hBoxLayout.setAlignment(alignment)
def setOrientation(self, orientation: PopupOrientation):
"""
设置抽屉的方向
:param orientation:
:return:
"""
self.__orientation = orientation
self.update()
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 e.type() == QEvent.MouseButtonRelease:
pos = e.pos()
if not self.widget.geometry().contains(pos):
self.fadeOut(0)
if obj is self.parent():
if e.type() == QEvent.Type.Resize:
re = QResizeEvent(e)
self.resize(re.size())
return super().eventFilter(obj, e)
class DrawerMaskDialog(PopupMaskDialogBase):
def __init__(self, parent=None):
super().__init__(parent)
self.vBox = QVBoxLayout(self.widget)
self.vBox.setAlignment(Qt.AlignTop)
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))
self.setAlignment(Qt.AlignTop)
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_())
演示