前言
本系列文章为b站PySide6教程以及官方文档的学习笔记
原视频传送门如下
官方文档链接:Qt for Python
创建选项卡
QTabWidget
提供了一个管理多个页面的堆栈,每个页面都有自己的选项卡标签。这使得用户可以通过选择不同的选项卡来切换不同的内容页面。
首先我们可以多创建几个QWidget
实例,将其作为选项卡中的不同页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| self.tab1 = QWidget() self.tab1Layout = QVBoxLayout() self.tab1Layout.addWidget(QPushButton('Button1')) self.tab1Layout.addWidget(QLabel('Label1')) self.tab1.setLayout(self.tab1Layout)
self.tab2 = QWidget() self.tab2Layout = QVBoxLayout() self.tab2Layout.addWidget(QPushButton('Button2')) self.tab2Layout.addWidget(QLabel('Label2')) self.tab2.setLayout(self.tab2Layout)
self.tab3 = QWidget() self.tab3Layout = QVBoxLayout() self.tab3Layout.addWidget(QPushButton('Button3')) self.tab3Layout.addWidget(QLabel('Label3')) self.tab3.setLayout(self.tab3Layout)
|
接下来我们创建一个选项卡QTabWidget
实例,并使用addTab
方法向其中添加页面
1 2 3 4
| self.tab = QTabWidget() self.tab.addTab(self.tab1, 'Tab1') self.tab.addTab(self.tab2, 'Tab2') self.tab.addTab(self.tab3, 'Tab3')
|
效果如下
常用属性和方法
前面创建的选项卡离真实软件中的选项卡样式还有很大差距
以Vscode中的选项卡为例,它不仅有关闭按钮和上下文菜单,还可以进行拖动
这需要我们配置选项卡的高级属性和方法
我们可以使用setTabsClosable
方法为选项卡增加关闭按钮
1
| self.tab.setTabsClosable(True)
|
使用setMovable
方法让选项卡能够被拖动
1
| self.tab.setMovable(True)
|
此时选项卡就拥有关闭按钮且可拖动了,当然关闭功能还需绑定信号和槽
常用信号
tabCloseRequested
信号会在我们点击关闭按钮时触发,并返回关闭的选项卡的信号
我们可以将其与removeTab
方法绑定,实现关闭选项卡的功能
1
| self.tab.tabCloseRequested.connect(lambda index: self.tab.removeTab(index))
|
剩下的三个信号也比较常用,后续在实践中也会用到
QStackedWidget
是一个容器控件,它可以包含多个子控件,但在任何给定时间只显示其中一个子控件。这对于实现向导界面或在同一位置显示不同内容的应用程序非常有用。
创建堆叠容器
与 QTabWidget
类似,我们可以通过创建多个 QWidget
实例作为不同的页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| self.stack1 = QWidget() self.stack1Layout = QVBoxLayout() self.stack1Layout.addWidget(QPushButton('Stack Button 1')) self.stack1Layout.addWidget(QLabel('Stack Label 1')) self.stack1.setLayout(self.stack1Layout)
self.stack2 = QWidget() self.stack2Layout = QVBoxLayout() self.stack2Layout.addWidget(QPushButton('Stack Button 2')) self.stack2Layout.addWidget(QLabel('Stack Label 2')) self.stack2.setLayout(self.stack2Layout)
self.stack3 = QWidget() self.stack3Layout = QVBoxLayout() self.stack3Layout.addWidget(QPushButton('Stack Button 3')) self.stack3Layout.addWidget(QLabel('Stack Label 3')) self.stack3.setLayout(self.stack3Layout)
|
使用addWidget
方法将页面添加到堆叠容器中。初始情况下,QStackedWidget
会显示第一个添加的页面
1 2 3 4
| self.stackedWidget = QStackedWidget() self.stackedWidget.addWidget(self.stack1) self.stackedWidget.addWidget(self.stack2) self.stackedWidget.addWidget(self.stack3)
|
效果如下
切换页面
可以使用 setCurrentIndex
或 setCurrentWidget
方法来切换 QStackedWidget
中当前显示的页面:
1 2 3
| self.stackedWidget.setCurrentIndex(1)
self.stackedWidget.setCurrentWidget(self.stack3)
|
setCurrentIndex
传入页面的序号,而setCurrentWidget
传入页面的实例名称
QStackedWidget
本身没有提供动画切换页面的功能。但是,我们可以通过结合使用 QPropertyAnimation
来实现页面之间的平滑过渡动画。
过渡动画
我们新建一个堆叠页面的类,在其中重写setCurrentIndex
函数,并加入动画效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class AnimatedStackedWidget(QStackedWidget): def __init__(self, parent=None): super().__init__(parent) self.animation = QPropertyAnimation(self, b"geometry") self.animation.setDuration(300)
def setCurrentIndex(self, index): self.animation.stop() current_widget = self.currentWidget() next_widget = self.widget(index)
stacked_widget_geometry = self.geometry() next_widget_start_geometry = QRect(stacked_widget_geometry.x(), stacked_widget_geometry.y() + stacked_widget_geometry.height()/4, stacked_widget_geometry.width(), stacked_widget_geometry.height()) next_widget_end_geometry = stacked_widget_geometry
next_widget.setGeometry(next_widget_start_geometry)
self.animation.setTargetObject(next_widget) self.animation.setStartValue(next_widget_start_geometry) self.animation.setEndValue(next_widget_end_geometry) super().setCurrentIndex(index) self.animation.start()
|
这里使用了QtCore
中的动画类QPropertyAnimation
,并设置为位置动画,即平移
切换到新页面时会从下往上平移加载
最后我们在页面中添加几个切换按钮
1 2 3 4 5 6 7 8 9
| for i in range(3): btn = QPushButton(f"Go to page {i+1}") btn.clicked.connect(self.make_switcher(i)) self.mainLayout.addWidget(btn) def make_switcher(self, index): def switch(): self.stackedWidget.setCurrentIndex(index) return switch
|
效果如下
当然我们也可以加一下判断条件,让动画更丝滑
比如当新的页面被切换时,动画还没播放完,则停止当前动画