Python 图形开发:PyQt 信号与槽机制

1. 信号与槽机制的引入

在绝大多数 GUI 库中,每个事件的发生往往伴随十分详细的信息,以供开发人员使用。
例如鼠标点击的精确坐标、按钮是通过鼠标按下还是通过空格键按下等等。
然而很多情况下,我们并不需要知道这些行为具体是如何发生的,只需要知道用户想要做些什么。
例如,我们只关心哪个按钮被按下,而不用知道用户是如何按下这个按钮的。

也就是说,对于低层次的具体细节,我们并不需要知道那么多。
相反,我们关心的是高层次的行为事件。
为此,Qt 提出了信号与槽的概念,抛开具体的细节,将一些行为抽象为某个信号;
而针对这些行为做出的反应,我们称之为槽。

简单来说,用户做出的某些行为会发出特定信号,而槽就是用来处理这些信号的函数。

2. 信号与槽机制的优点

信号极大精简了事件发生的信息,保留了最核心的部分。

例如,当我们修改 QTextEdit 文本编辑框的内容时,QObject 将这一行为所触发的事件通过多种信号发送出来:有 textChanged 信号,表示内容被改变,还有 cursorPositionChanged 信号,表示光标位置被改变等等。

我们可以关注特定信号,将它们连接到对应的处理函数中,即前边提到的槽,而忽略其它不必要的信号。

3. 信号与槽的连接

信号发出后,如果没有被连接到槽中,则默认会被忽略。

我们将所关心的信号通过以下语法与槽进行连接:

s.connect(w, SIGNAL("signalSignature"), functionName)
s.connect(w, SIGNAL("signalSignature"), instance.methodName)
s.connect(w, SIGNAL("signalSignature), instance, SLOT("slotSignature"))

s 表示发出信号的组件所属的 QObject,在类中通常为 self。w 表示发出信号的组件。
signalSignature 即信号的名字,它可以不带参数,也可以带上以逗号分隔的参数列表,用括号包围起来。如果信号是个 Qt 信号,那么参数类型必须是 C++ 类型,例如 int 或 QStringg。PyQt 信号是在真正发送时被定义的,它可以带有任意数量、任意类型的参数。

slotSignature 与 signalSignature 类似,只不过对应的是槽。槽接收的参数不能比信号发出时的参数还要多,但可以比它少。如果槽的参数少于信号的参数,则多余信号参数将被忽略。信号与槽的对应参数必须具有相同的类型。

我们通过使用 QObject.connect() 来进行信号的连接,也可以使用 QObject.disconnect() 来切断连接。
但在实际使用中,我们很少需要手动切断连接,因为 PyQt 会自动切断被删除对象的相关连接。

除了能够连接信号和槽,信号与信号之间也能进行连接。两个信号相连接的效果是,当第一个信号发送时,会引起第二个信号的发送。

4. 信号的格式

在 Python 中,连接信号的形式较为灵活。例如,有一个 valueChanged(int) 信号,我们在连接时可以根据需要使用以下三种写法:

self.connect(spinBox, SIGNAL("valueChanged(int)"), func1)
self.connect(spinBox, SIGNAL("valueChanged()"), func2)
self.connect(spinBox, SIGNAL("valueChanged"), func3)

第一种写法是标准的信号格式:在括号里带上随信号发出的参数类型。如果 func1 不接收任何参数,则这些参数将被忽略。

第二种写法表示信号发送时不携带任何参数,因此所连接的 func2 应该是一个不接收额外参数的可调用对象。

第三种写法是 PyQt 中特有的短路信号,我们可以在信号发送时携带任意的 Python 对象。

如果使用带参数的信号形式,则这些参数会被转换成 C++ 中的数据类型。而如果使用的是短路信号,则不会进行任何转换,所有的 Python 数据结构或者自定义类型都能够作为参数传递。这样一来,当我们需要传递一些复杂的数据类型时,就可以使用短路信号。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注