前言

  Qt 内置了非常棒的 信号槽的函数。
  可以让 UI 进行异步调用。
  但是有些时候,并不想依赖 Qt 框架同时又能实现信号槽的功能。
  这里可以使用 blinker 库来完成。

Github 地址
官方说明文档

blinker 基本用法

1
2
3
4
5
from blinker import signal,Signal

initialized = signal('initialized')
initialized is signal('initialized')
sig = Signal()

  可以使用匿名信号槽,也可以使用带名称的信号槽。


1
2
3
4
5
6
7
8
9
from blinker import signal
send_data = signal('send-data')
@send_data.connect
def receive_data(sender, **kw):
print("Caught signal from %r, data %r" % (sender, kw))
return 'received!'
result = send_data.send('anonymous', abc=123)
print(result) # 打印 [(<function receive_data at 0x000002A3328D4DC8>, 'received!')]
# 打印 Caught signal from 'anonymous', data {'abc': 123}

  可以用装饰器的方式连接信号槽
  触发信号槽使用 send 方法
  并且信号槽执行完可以拿到函数触发的返回值。


1
2
3
4
5
6
7
8
9
from blinker import signal

dice_roll = signal('dice_roll')
@dice_roll.connect_via(1)
@dice_roll.connect_via(3)
@dice_roll.connect_via(5)
def odd_subscriber(sender):
print("Observed dice roll %r." % sender)
result = dice_roll.send(3)

  另外一个特点就是可以根据触发的参数去触发相应注册的函数。
  Qt 因为要使用 C++,这种注册方式会非常麻烦。


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
from blinker import signal

initialized = signal("initialized")


@initialized.connect
def initialize_call1():
print("initialize_call1")


@initialized.connect
def initialize_call2():
print("initialize_call2")


@initialized.connect
def initialize_call3():
print("initialize_call3")


for key, weakref in initialized.receivers.items():
func = weakref()
func()

# 打印:
# initialize_call1
# initialize_call2
# initialize_call3

  通过信号槽的 receivers 方法可以获取到注册到信号槽的所有函数。

总结

  这个库可以摆脱 Qt 的依赖实现函数的异步调用。
  如果是 Qt 的环境建议还是使用 Qt 内置的 信号槽,这样可以支持 Qt 的多线程等处理。
  但如果是 Python 环境下想要摆脱 Qt 的依赖,则推荐 blinker 来完成信号触发。
  blinker 还有个好处是可以获取到注册的函数列表,而 Qt 基于 C++ 的并没有提供这个功能,只能通过 Meta 对象来判断这个信号槽是否有函数连接。 参考实现