代码
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_( ) )
演示