PySide6 自定义侧边栏 实现思路与代码详解
PySide6虽然得益于Qt框架的强大与Python语法的快速开发,但是默认提供的主题不符合现代UI的省美!比如:侧边栏一般也叫导航栏(更多是手机平板的等设备)。
写在前边
笔者使用的是Linux的Gnome桌面系统,其他显示效果请自行尝试!
为了更方便的描述,这里分为如下俩中情况:
- 默认展开 => 切换后先收缩
- 默认收缩 => 切换后先放大
效果演示
默认展开
注意:
- 紫色为:
QFrame嵌套QVboxLayout是主窗口 - 绿色为:
QFrame嵌套QVboxLayout是侧边栏(父类为主窗口的QFrame)
实现思路
显示与隐藏核心:
- 默认展开:
QFrame设置最大与最小宽度为155 - 切换:重新设置
QFrame的最小宽度
温馨提示:
setFixedWidth<=>setMinimumWidth+setMaximumWidth
选择QFrame一是参考Qt Designer,二是继承QWidget更好的设置 属性
核心代码解读
deftoggle_sidebar(self):"""show or hide toggle button text"""self.anim=QPropertyAnimation(self.__sidebar_frame,b"minimumWidth")self.anim.stop()ifself.__sidebar_visible==False:# hide: right to leftself.anim.setStartValue(self.__sidebar_frame.width())self.anim.setEndValue(40)else:# show: left to rightself.anim.setStartValue(self.__sidebar_frame.width())self.anim.setEndValue(155)self.__sidebar_frame.setFixedWidth(40)self.anim.setEasingCurve(QEasingCurve.Type.InOutQuad)self.anim.setDuration(500)self.anim.start()self.__sidebar_visible=notself.__sidebar_visible重点如下:
QPropertyAnimation:实现显示与隐藏的动画效果;官方文档QEasingCurve:使得动画更丝滑;官方文档setDuration:设置动画的持续时间;官方文档
⚠️注意:
- 取消
self.__sidebar_frame.setFixedWidth(40)将无法正常收缩- 改变整体布局为
QHBoxLayout,展开与收缩就会从QFrame中心垂线收缩与展开
完整代码:
#hide_sidebar.pyimportsysfromPySide6.QtWidgetsimport(QWidget,QFrame,QVBoxLayout,QPushButton,QApplication)fromPySide6.QtCoreimportQPropertyAnimation,QEasingCurveclassQCustomeWidget(QWidget):"""Custome sidebar """def__init__(self):self.__sidebar_visible=Falsesuper().__init__()self.__setup_ui()self.__setup_event_handel()def__setup_ui(self):# widget sizeself.setFixedSize(400,300)# global layout use framelayout then vboxlayoutself.__global_frame=QFrame(self)self.__global_frame.setContentsMargins(0,0,0,0)self.__global_layout=QVBoxLayout(self.__global_frame)self.__global_layout.setSpacing(0)self.__global_layout.setContentsMargins(0,0,0,0)# sidebar frame framelayoutself.__sidebar_frame=QFrame(self.__global_frame)self.__sidebar_layout=QVBoxLayout(self.__sidebar_frame)self.__sidebar_frame.setLayout(self.__sidebar_layout)self.__sidebar_frame.setContentsMargins(0,0,0,0)self.__sidebar_layout.setContentsMargins(0,0,0,0)self.__sidebar_layout.setSpacing(0)# form sizeself.__sidebar_frame.setFixedSize(155,self.height())self.__sidebar_frame.setStyleSheet("background-color:grey;")# toggle and home buttonself.__toggle_btn=QPushButton('show: button text',self.__sidebar_frame)self.__toggle_btn.setStyleSheet(".QPushButton {background-color: rgb(56, 56, 60);text-align: left;}")self.__home_btn=QPushButton('home: button text',self.__sidebar_frame)self.__home_btn.setStyleSheet(".QPushButton {background-color: rgb(56, 56, 60);text-align: left;}")# add buttonself.__sidebar_layout.addWidget(self.__toggle_btn)self.__sidebar_layout.addWidget(self.__home_btn)# add Widgetself.__global_layout.addWidget(self.__sidebar_frame)def__setup_event_handel(self):self.__toggle_btn.clicked.connect(self.toggle_sidebar)deftoggle_sidebar(self):"""show or hide toggle button text"""self.anim=QPropertyAnimation(self.__sidebar_frame,b"minimumWidth")self.anim.stop()ifself.__sidebar_visible==False:# hide: right to leftself.anim.setStartValue(self.__sidebar_frame.width())self.anim.setEndValue(40)else:# show: left to rightself.anim.setStartValue(self.__sidebar_frame.width())self.anim.setEndValue(155)self.__sidebar_frame.setFixedWidth(40)self.anim.setEasingCurve(QEasingCurve.Type.OutQuad)self.anim.setDuration(500)self.anim.start()self.__sidebar_visible=notself.__sidebar_visibledefmain():app=QApplication([])sidebar=QCustomeWidget()sidebar.show()sys.exit(app.exec())if__name__=="__main__":main()默认隐藏
注意:
- 紫色为:
QFrame嵌套QVboxLayout或QHboxLayout是主窗口 - 绿色为:
QFrame嵌套QVboxLayout是侧边栏(父类为主窗口的QFrame)
实现思路
与默认展开不同的是:
- 右侧需要控件用于占用剩余的空间.
完整代码
#show_sidebar.pyimportsysfromPySide6.QtWidgetsimport(QWidget,QFrame,QHBoxLayout,QVBoxLayout,QLabel,QPushButton,QApplication)fromPySide6.QtCoreimport(QPropertyAnimation,QEasingCurve)classQCustomeSideBar(QWidget):"""Custome sidebar """def__init__(self):self.__sidebar_visible=Falsesuper().__init__()self.__setup_ui()self.__setup_event_handel()def__setup_ui(self):# widget sizeself.setFixedSize(400,300)# global layout use framelayout then vboxlayoutself.__global_frame=QFrame(self)self.__global_frame.setContentsMargins(0,0,0,0)self.__global_layout=QVBoxLayout(self.__global_frame)# or use# self.__global_layout = QHBoxLayout(self.__global_frame)self.__global_layout.setSpacing(0)self.__global_layout.setContentsMargins(0,0,0,0)# content and sidebar frame framelayoutself.__sidebar_frame=QFrame(self.__global_frame)self.__sidebar_layout=QVBoxLayout(self.__sidebar_frame)self.__sidebar_frame.setLayout(self.__sidebar_layout)self.__sidebar_frame.setContentsMargins(0,0,0,0)self.__sidebar_layout.setContentsMargins(0,0,0,0)self.__sidebar_layout.setSpacing(0)# form sizeself.__sidebar_frame.setFixedSize(40,self.height())self.__sidebar_frame.setStyleSheet("background-color:grey;")# toggle and home buttonself.__toggle_btn=QPushButton('show: button text',self.__sidebar_frame)self.__toggle_btn.setStyleSheet(".QPushButton {background-color: rgb(56, 56, 60);text-align: left;}")self.__home_btn=QPushButton('home: button text',self.__sidebar_frame)self.__home_btn.setStyleSheet(".QPushButton {background-color: rgb(56, 56, 60);text-align: left;}")# add buttonself.__sidebar_layout.addWidget(self.__toggle_btn)self.__sidebar_layout.addWidget(self.__home_btn)# add Widgetself.__global_layout.addWidget(self.__sidebar_frame)self.__content_button=QLabel("text")self.__content_button.setStyleSheet("text-align: right; margin-left:115px;")self.__global_layout.addWidget(self.__content_button)def__setup_event_handel(self):self.__toggle_btn.clicked.connect(self.toggle_sidebar)deftoggle_sidebar(self):"""show or hide toggle button text"""self.anim=QPropertyAnimation(self.__sidebar_frame,b"minimumWidth",self.__global_frame)self.anim.stop()ifself.__sidebar_visible==False:# show: left to rightself.anim.setStartValue(self.__sidebar_frame.width())self.anim.setEndValue(155)else:# hide: right to leftself.anim.setStartValue(self.__sidebar_frame.width())self.anim.setEndValue(40)self.anim.setEasingCurve(QEasingCurve.Type.InOutQuad)self.anim.setDuration(500)self.anim.start()self.__sidebar_visible=notself.__sidebar_visibledefmain():app=QApplication([])sidebar=QCustomeSideBar()sidebar.show()sys.exit(app.exec())if__name__=="__main__":main()一起学习与探讨
点击链接加入群聊【PySide6学习交流群】: