信号与槽函数
信号(Signal)
信号是在特定情况下被发射的一种通告。举例:
PushButton的信号是鼠标单击时发射的clicked信号
槽(Slot)
对信号相应的函数。举例:
Qwidget有一个槽函数,功能是关闭窗口
信号与槽的关系
一个信号可以关联多个槽函数
一个信号可以关联其他信号
信号的参数可以是任何Python数据类型
一个槽函数可以和多个信号关联
关联可以是直接的(同步)或排队的(异步)
可以在不同的线程之间建立关联
信号与槽可以断开关联
本次例子实现具体效果
实现效果类似于自定义字体的颜色,大小和样式等等,效果图如下
创建目录
e:\baikejia\bkj2-3
创建Qt项目QtApp
e:\baikejia\bakj2-3\QtAp
注意选择QDialog作为基类
组件布局管理
初始窗体
放一个GroupBox和三个CheckBox
在窗体上部放一个Group Box,Group Box的title属性设为空。
往Group Box放三个CheckBox组件,不用刻意去调整位置
三个CheckBox的ObjectName分别设为chkBoxUnder、chkBoxItalic、chkBoxBold,text分别设为Underline、Italic、Bold,其中chkBoxUnder的checked属性打勾
放好后,右侧Object inspector应该如图所示
窗体显示如下
现在看起来,很不整齐
选中GroupBox,点击上方的水平布局按钮
点完后变整齐了
放一个GroupBox和三个Radio Button
三个Radio Button的ObjectName分别为radioBlack、radioRed、radioBlue,text分别为Black、Red、Blue,其中radioBlack的checked属性打勾
窗体是这样的
点击水平布局按钮后,窗体变成了这样
放一个PlainTextEdit
设置ObjectName为textEdit
放一个Horizontal Layout
在Horizontal Layout上面放三个PushButton和两个Horizontal Spacer
放一个Push Button
再放一个Push Button
再放一个Push Button
放一个Horizontal Spacer
再放一个Horizontal Spacer
放好后窗体如图所示
修改三个Push Button的ObjectName分别为:btnClear、btnOK、btnClose,Text分别为“清空”、“确定”、“关闭”
设置窗体布局
点窗体空白处,选中窗体
点击工具栏中的垂直布局按钮
窗口布局调整如下
适当改动窗口大小,形成如下最终窗体
设置组件tab顺序
点击工具栏上方的Edit Tab Order按钮
窗体显示如下
在理想的第一个Tab上点击右键,选择重新开始。如上图就在Underline左侧的5上点右键
点工具栏的❌关闭
设置信号和槽
对话框类Qdialog内置槽函数
accept():关闭对话框,表示肯定的选择,例如“确定”
reject():关闭对话框,表示否定的选择,例如“取消”
close():关闭对话框
将确定按钮与accept()槽函数关联
点击工具栏上的Edit Signals/Slots按钮
鼠标点击选中确定按钮,按住鼠标左键拖动到窗体空白区域后释放左键,弹出关联设置对话框
左边选clicked,右边选accept(),然后点OK。
底部的Signals Slots Editor出现一条数据
将关闭按钮与close()槽函数关联
右边没有close按钮,要选显示从QWidget继承的信号和槽
保存Qt项目,将ui文件拷贝到Eric6目录中
Eric6下创建项目
项目下只有一个__init__.py文件
选择窗体,编译
编译后查看文件
上面红色框框中的两行代码就是刚刚建好的信号与槽的关联
创建窗体业务逻辑类
按照界面与业务逻辑分离且界面独立封装的方式定义一个类QmyDialog,保存为myDialog.py。代码如下:
##与UI窗体类对应的业务逻辑类
import sys
from PyQt5.QtWidgets import QApplication, QDialog
from Ui_Dialog import Ui_Dialog
class QmyDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent) #调用父类构造函数,创建窗体
self.ui=Ui_Dialog() #创建UI对象
self.ui.setupUi(self) #构造UI界面
if __name__ == "__main__": #用于当前窗体测试
app = QApplication(sys.argv) #创建GUI应用程序
form=QmyDialog() #创建窗体
form.show()
sys.exit(app.exec_())
运行myDialog
myDialog可以直接运行
确定和退出两个按钮都可以正常使用。
这是因为在QmyDialog的构造函数__init__中创建了窗体类的实例对象self.ui,并调用了setupUi()函数。而SetupUi()函数实现了这两个按钮的信号与窗体相关槽函数的关联。
其他按钮还没填代码,所以不行。
建立应用程序主程序文件appMain.py
myDialog.py可以当作主程序直接运行,但是建议单独编写一个主程序文件appMain.py。
该文件的功能是创建应用程序和主窗体,然后显示主窗体,并开始运行应用程序。
appMain.py将myDialog.py文件的测试运行部分单独拿出来作为一个文件
当一个应用程序有多个窗体,并且窗体之间有数据传递时,appMain.py负责创建应用程序的主窗体并运行起来,这样使整个应用程序的结构更清晰
appMain.py的代码如下:
## GUI应用程序主程序
import sys
from PyQt5.QtWidgets import QApplication
from myDialog import QmyDialog
app = QApplication(sys.argv) #创建GUI应用程序
mainform=QmyDialog() #创建主窗体
mainform.show() #显示主窗体
sys.exit(app.exec_())
为组件的内建信号编写槽函数
清空按钮
为清空按钮添加槽函数
进入Qt Creator,右键点击清空按钮,选择转到槽
选择clicked
在弹出的文件中复制函数名
进入Eric6,在myDialog.py文件的QmyDialog类里定义一个同名函数并编写代码
添加PlainText的初始化函数
在Ui_Dialog.py中添加如下函数
在myDialog.py中添加对这个函数的调用
运行程序
按清空按钮
内容被清空
Bold复选框
编写代码
进入Qt Creator,为Bold复选框设置槽函数,选toggled(bool)
记下函数名
在myDialog.py文件的QmyDialog类里定义一个同名函数,并且具有相同类型的参数
运行程序
选择Bold复选框
可以看到里面字体加粗了
取消Bold复选框
字体没有加粗了
Underline复选框
编写代码
在Qt Creator中为Underline复选框添加槽函数,选择clicked()
在Ui_Dialog.py中添加如下函数
修改Ui_Dialog.py中的SetupUI函数
修改后变成
运行程序
选中Underline
信号与槽的管理是如何实现的
在QmyDialog类里定义了三个函数,这三个函数就与相应界面组件的信号关联起来了
在QmyDialog类的构造函数里并没有任何代码实现信号与槽的关联,Ui_Dialog也没有做任何修改。这些信号与槽的关联是怎么实现的?
看Ui_Dialog.py的SetupUi()函数的这一条语句
功能是搜索Dialog窗体上的所有从属组件,将匹配的信号和槽函数关联起来。只有符合命名规则的槽函数才会被匹配。不符合命名规则的函数不能自动与信号关联。
overload型信号的处理
Italic复选框
找到槽函数名
在Qt Creator中为Italic复选框设置槽函数,选择clicked(bool)
注意有一个clicked(),还有一个clicked(bool)。这两个都是clicked信号。默认情况下,connectSlotsByName只会关联默认的不带参数的clicked信号,不会关联带参数的clicked(bool)信号
要解决这个问题,需要使用@pyqtSlot修饰符,将函数的参数类型声明清楚
编写代码
在Ui_Dialog.py中添加如下函数
有警告,是因为import少了模块
这是myDialog.py中原有的import
添加import 模块
加了后,上面代码中的警告取消了
运行程序
手动关联信号与槽函数
实现设置颜色的三个RadioButton按钮的clicked()信号与同一个槽函数关联
添加import模块
添加自定义槽函数
在QmyDialog类里顶一个自定义槽函数do_setTextColor(self)
在构造函数中关联信号和槽函数
这就将三个RadioButton的clicked信号与同一个槽函数关联起来了
运行程序
补丁
问题
突然发现RadioBlue的text属性错了,郁闷
返回Qt Creator中将RadioBlue的text改为Blue
保存ui文件后,将e:\baikejia\bkj2-3\QtApp目录的Dialog.ui拷贝到e:\baikejia\bkj2-3下,覆盖原Dialog.ui文件
记得要在Eric6下重新编译form
运行出错
重新运行,发现报错
这是因为重新编译了ui文件,导致ui_Dialog.py文件内容更新,刚才在里面放的do_setTextEdit被冲掉了。只好补回去
补充代码
运行程序
终于好了。注意要运行appMain.py,不要运行Ui_Dialog.py