本文以堆叠窗口控件为例,详细介绍堆叠布局的界面设计和程序实现过程,通过案例带小白创建一个典型的堆叠布局多窗口切换程序
软件项目中经常需要多种不同的图形界面,以适应不同的任务场景。选项卡控件(QTackedWidget)通过标签选择打开对应的对话框页面,不需要另外编程。堆叠窗口控件(QStackedWidget)在主程序中通过编程来控制显示的图形界面,相对比较复杂,但也更加通用和灵活。
布局管理就是管理图形窗口中各个部件的位置和排列。图形窗口中的大量部件也需要通过布局管理,对部件进行整理分组、排列定位,才能使界面友好。上一篇文中我们介绍了基本的水平布局、垂直布局、栅格布局、表格布局和进阶的嵌套布局和容器布局。
在容器布局中,通过容器控件(Containers)与布局管理器(Layouts)的结合,可以实现对程序窗口的分割和布局,就可以自由设计各种丰富的图形界面。
在实际的软件项目中,通常需要多种/多个不同的图形界面,以适应不同的任务场景。如何实现多窗口图形界面的需求呢?大致来说有几种思路:
使用弹出窗口。主窗口提供基本界面,通过弹出窗口实现子任务界面,子任务结束后关闭弹出窗口回到主窗口。
这是一种可行的,也比较简单的处理方案,很多应用程序中都设有弹出窗口。但是频繁弹出和关闭窗口的用户体验不好,而且在窗口之间的切换不方便。
重建图形界面。当调用新的图形界面时,关闭后删除现有界面上的所有控件,再新建需要的各种控件。
这种方案虽然可行,但是编程复杂、浪费资源、容易出错,难以适应多窗口相互切换的要求,因此很少使用。在 QtDesigner 中也不支持这种方案的操作。
通过堆叠布局实现多窗口切换。堆叠布局是在窗口的整体或局部区域设置多组图形界面,根据需要使用指定的图形界面。
打个比方,这就好比戏剧或拍照中准备了多种背景幕布,需要什么场景,就展开所需的场景幕布,而把其它幕布收起来。
QStackedLayout 类提供了多页面切换的堆叠布局。
选项卡控件(QTackedWidget)提供了选项卡对话框,外观类似于浏览器页面打开多个标签页。选项卡控件允许创建多个对话框页面,每个页面带有自己的标签。使用时点击标签行进行选择,就打开对应的对话框页面,不需要另外编程。
堆叠窗口控件(QStackedWidget)提供了更加通用和灵活的多窗口、多页面切换的解决方案。QStackedWidget 控件可以添加在整个窗口或窗口中的任意区域,允许在堆叠窗口区域内设计多个页面,在程序控制使用指定的窗口界面。
堆叠窗口控件(QStackedWidget)需要在主程序中通过编程来控制显示的图形界面,相对于选项卡控件(QTackedWidget) 来说比较复杂,但因此也更加灵活。
本文以堆叠窗口控件(QStackedWidget)为例,详细介绍堆叠布局的界面设计和程序实现过程。
(1)以上文 uiDemo6.ui 为基础:图形窗口的左侧上部为垂直布局的按钮控件区域 leftLayout_1,设有多个按钮控件,用于选择不同的业务;左侧下部为垂直布局的文本区域 leftLayout_2,设有文本显示框。
(2)将图形窗口右侧的主体区域设计为堆叠窗口,用于设计多个图形界面,以适应不同的业务场景:
在 QtDesigner 左侧工具栏 “Containers” 类中,选择 “Stacked Widget” 控件,将其拖动至设计的图形窗口中,创建堆叠布局的容器控件。
对窗口中的堆叠容器 “Stacked Widget”,选中后可以用鼠标拖动、拉伸来调整控件的位置和大小,或者在 “属性编辑器” 中设置 (X, Y)、宽度、高度属性。
堆叠容器 “Stacked Widget” 自动建立了 2个页面。鼠标位于堆叠容器 “Stacked Widget” ,右键唤出下拉菜单,选择 "插入页"可以插入新的页面,选择 “改变页顺序” 可以调整各页面的顺序。
在控件的右上角显示有一对黑色三角符号,可以在多个页面之间切换,也可以在 “对象查看器” 中选择要编辑的页面。
(3)堆叠容器 “Stacked Widget” 中各页面的设计,具体设计内容是根据业务需要确定的。
page_0 的设计:标签控件 label_1 用于显示封面图片,按钮控件 pushButton_6~8 用于控制翻页;
page_1 的设计:水平布局的标签控件 label_2、label_3 用于显示原始图片和处理图片,控件用于控制处理方法和参数,按钮控件 pushButton_9~11 用于控制翻页;
page_2 的设计:表格控件 tableWidget 控件用于显示表格数据,按钮控件用于控制。
将完成的堆叠布局界面设计文件另存为 uiDemo8.ui,不同页面的编辑状态如下图所示:
堆叠布局 page_0 设计图:
堆叠布局 page_1 设计图:
堆叠布局 page_2 设计图:
使用堆叠窗口控件(QStackedWidget)建立的堆叠布局界面,要在主程序中通过编程控制显示哪一个图形界面。
QStackedWidget 类继承自 QFrame类。QStackedWidge t类提供了多页面切换的布局,一次只能看到一个界面。
QStackedWidget 类的信号:
currentChanged(int index):当前页面发生变化时候发射,index 为新的索引值。
widgetRemoved(int index):页面被移除时候发射,index 为页面对应的索引值。
QStackedWidget 类的槽函数:
setCurrentIndex(int index):设置索引 index 所在的页面为当前页面。
setCurrentWidget(QWidget *widget):设置QWidget页面为当前页面。
简单地说,使用如下程序可以设置 page_0 为当前显示的页面:
pageNo =0 # 设置 page_0 为索引页(第一页面)
self.stackedWidget.setCurrentIndex(pageNo) # 设置使用 pageNo=0 作为当前显示页面
需要注意的是,不论我们为每个页面控件设置的名称(objectName)是什么,在 QStackedWidget 类中定义的页面索引 index 都是一个从 0 开始计数,即:第一页面的索引值 index=0,第二页面的索引值 index=1,…。
因此,为了避免混淆,建议将 StackedWidge 控件的第一页面命名为 objectName: page_0,第二页面命名为 objectName: page_1,…
建立信号/槽连接,既可以在 QtDesigner 中设置,也可以在主程序中通过程序实现。
以下例程是在程序中建立信号/槽连接。
# 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
self.pushButton_1.clicked.connect(self.click_pushButton_1) # 点击 pushButton_1 触发
self.pushButton_2.clicked.connect(self.click_pushButton_2) # 点击 pushButton_2 触发
self.pushButton_3.clicked.connect(self.click_pushButton_3) # 点击 pushButton_3 触发
通过编程控制堆叠窗口控件的显示页面,就是说当前显示哪一个图形界面。
一种简单的方法是,在任务场景的子程序中,直接使用 setCurrentIndex() 设置选择堆叠控件的显示页面。通俗的说就是,任务需要使用哪个场景时,就在程序中编写页面设置语句进行选择。例如:
defclick_pushButton_1(self): # 点击 pushButton_1 触发
self.textEdit.append("当前动作:click_pushButton_1")
self.textEdit.append("选择堆叠布局页面:page_0")
self.stackedWidget.setCurrentIndex(0) # 打开 stackedWidget > page_0
self.label_1.setPixmap(QtGui.QPixmap("../image/fractal01.png"))
return
另一种高级的应用方法是,通过自定义页面控制函数,获取当前信号 sender 检索 objectName,来选择堆叠窗口控件的显示页面。这种方法更清晰地体现业务与界面的分离。例如:
defframeController(self): # 页面控制函数
sender =self.sender().objectName() # 获取当前信号 sender
index ={
"pushButton_1": 0, # page_0
"pushButton_2": 1, # page_1
"pushButton_3": 2, # page_2
}
self.stackedWidget.setCurrentIndex(index[sender]) # 根据信号 index 设置所显示的页面
控件操作包括控件发出信号和在槽函数中进行操作。
在用户编写的程序中,需要接收控件信号、或在槽函数中对控件进行操作,都要通过控件的 objectName 来实现。
例如,点击按钮 “第一章”(pushButton_1),就选择堆叠布局页面 “page_0”;要在标签控件 “label_1” 显示图片 “…/image/fractal01.png”,就使用以下的程序:
self.label_1.setPixmap(QtGui.QPixmap("../image/fractal01.png"))
而对于堆叠布局页面 “page_0” 中的按钮控件 “上一张”、“下一张”、“返回”,要实现点击按钮时执行相应的任务,则应以控件的 objectName 建立触发信号与槽函数的连接。例如:
# 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
self.pushButton_6.clicked.connect(self.click_pushButton_6) # 点击按钮 "上一张" 触发
self.pushButton_7.clicked.connect(self.click_pushButton_7) # 点击按钮 "下一张" 触发
self.pushButton_8.clicked.connect(self.click_pushButton_8) # 点击按钮 "返回" 触发
需要特别提醒的是:堆叠布局的每个页面中的各个控件都是相互独立的不同的控件,具有不同的控件名称 objectName。
例如,page_0 中的按钮控件 “上一张”、“下一张”,与 page_1 中的按钮控件 “上一张”、"下一张"是不同的控件,具有不同的控件名称 objectName。
从 QtDesigner 可以清楚地看到所有控件名称及隶属关系。“stackedWidget” 堆叠布局页面 “page_0” 中的按钮控件 “上一张”、“下一张”、“返回”,objectName 分别是 pushButton_6、pushButton_7、pushButton_8;而页面 “page_1” 中的按钮控件 “上一张”、“下一张”、“返回”,objectName 分别是 pushButton_9、pushButton_10、pushButton_11。
先上两张程序运行结果图。
我们的图形窗口如图所示,看起来已经有模有样了。