PyQt入门(2)-信号和槽

信号和槽用于对象之间的通信。

信号和槽机制是 Qt 的核心特性,可能也是与其他框架最不同的地方。Qt的元对象系统使信号和槽成为可能。

在 GUI 编程中,当我们更改一个 widget 时,我们通常希望通知另一个 widget。更普遍地说,我们希望任何类型的对象都能够相互通信。例如,如果用户单击关闭按钮,我们可能希望调用窗口的
close()函数。

其他框架使用回调实现这种通信,在 Qt 中,我们有回调技术的替代方法:

我们使用信号和槽,当特定事件发生时会发出信号。Qt 的widget有许多预定义的信号,但我们总是可以将widget子类化以向它们添加我们自己的信号。插槽是响应特定信号而调用的函数。Qt 的widget有许多预定义的插槽,但通常的做法是将widget子类化并添加您自己的插槽,以便您可以处理您感兴趣的信号。

信号和槽的详细介绍

详情应该去看官网文档,这里简单总结以下这些核心要点:

1. 信号和槽的使用依赖于QObject上下文,就是说必须在QObject或者其子类中以类成员变量的方式定义信号,其他地方定义的信号是无效的。信号与槽的连接和信号的发射就无所谓了,放在哪里都可以。

from PyQt5.QtCore import QObject, pyqtSignal

class ContextObject(QObject):
    # 信号只能定义在这里
    my_signal = pyqtSignal()

def my_solt():
    print('i get the signal.')

if __name__ == "__main__":
    context = ContextObject()
    # 连接信号和槽
    context.my_signal.connect(my_solt)
    # 发射信息
    context.my_signal.emit()
    print('over')

"""
i get the signal.
over
"""

说明:

必须要实例化ContextObject,在代码中直接以ContextObject.my_signal.connect(my_solt)的方式连接信号和槽是无效的,因为这时没有上下文环境,my_signal还没有添加connect、emit等方法

2. 信号的签名必须与槽的签名相匹配,槽的签名可以比信号的签名短,但不能比它长。使用emit发射信号时,参数的数量和类型必须与定义信号时的严格对应。

from PyQt5.QtCore import QObject, pyqtSignal

class ContextObject(QObject):
    my_signal = pyqtSignal(str, int)

def my_solt1():
    print('my_solt1')

def my_solt2(a):
    print('my_solt2:', a)

def my_solt3(a, b):
    print('my_solt3:', a, b)

def my_solt4(a, b, c):
    print('my_solt4:', a, b, c)

if __name__ == "__main__":
    context = ContextObject()
    context.my_signal.connect(my_solt1) # my_solt1
    context.my_signal.connect(my_solt2) # my_solt2: 2
    context.my_signal.connect(my_solt3) # my_solt3: 2 3
    context.my_signal.connect(my_solt4) # TypeError: my_solt4() missing 1 required positional argument: 'c'
    context.my_signal.emit("2", 3)
    context.my_signal.emit(2, 3) # TypeError: ContextObject.my_signal[str, int].emit(): argument 1 has unexpected type 'int'
    print('over')


3. 一个信号可以连接任意多个槽,一个槽可以连接到任意多个信号上

from PyQt5.QtCore import QObject, pyqtSignal

class ContextObject(QObject):
    my_signal1 = pyqtSignal(str, int)
    my_signal2 = pyqtSignal(int)

def my_solt1():
    print('my_solt1')

def my_solt2(a):
    print('my_solt2:', a)

if __name__ == "__main__":
    context = ContextObject()
    context.my_signal1.connect(my_solt1)
    context.my_signal1.connect(my_solt2)
    context.my_signal2.connect(my_solt1)
    context.my_signal2.connect(my_solt2)
    print('my_signal1')
    context.my_signal1.emit("2", 3)
    print('my_signal2')
    context.my_signal2.emit(5)
    print('over')

"""
my_signal1
my_solt1
my_solt2: 2
my_signal2
my_solt1
my_solt2: 5
over
"""

4. 信号的发射与槽的调用是同步的,即只有所有槽都按顺序挨个调用完成之后,emit()之后的代码才会继续执行

5. 使用lambda表达式给无参数信号携带参数

class ContextQObject(QObject):
    my_signal = pyqtSignal()

def func(num, count):
    print(num, count)

if __name__ == '__main__':
    my = ContextQObject()
    a = 222
    b = 333
    my.my_signal.connect(lambda : func(a, b))
    my.my_signal.emit()
输出:222 333

6. 使用functools下的partial给无参数信号携带参数

class ContextQObject(QObject):
    my_signal = pyqtSignal()

def func(num, count):
    print(num, count)

if __name__ == '__main__':
    my = ContextQObject()
    a = 222
    b = 333
    my.my_signal.connect(partial(func, a, b))
    my.my_signal.emit()
输出:222 333

第5条和第6条一般用来扩展PyQt5的内置信号,因为很多内置信号都是未定义参数的,但有时候我们又有传输参数的需求。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值