我正在学习PyQt(之前我没有使用过C ++ Qt)。
我不明白信号和插槽的原因。 也就是说,我似乎可以通过直接调用类的方法来完成所有操作。 这样做似乎更Pythonic,使用更少的代码,更容易阅读。 我错过了什么?
为了澄清,我问为什么我会这样做:
def mouseReleaseEvent(self):
self.clicksignal.connect(ui.iconClicked)
self.clicksignal.emit()
当我能做到这一点:
def mouseReleaseEvent(self):
ui.iconClicked()
信号和插槽存在的原因是因为除了UI线程之外,您无法从应用程序的任何其他线程更改GUI。
如果你要做一些繁重的CPU密集型计算,或者等待IO或类似的任何任务...如果你这样做UI线程(例如,如果你获取一个url或持续一段时间的东西),你的UI线程将忙,GUI事件循环将无法自行更新,因此GUI似乎已冻结。
做这些操作。您在一个单独的(后台工作程序)线程中执行它们,因此UI线程可以继续更新GUI。
现在的问题是,您无法访问GUI的元素并从除UI线程之外的任何其他线程更改其状态。因此引入了信号和插槽。当您发出信号时,它确保被捕获在UI线程中,并且插槽将在UI线程中执行。
我不确定你在你的例子中想要完成什么,但这是信号和插槽存在的主要原因。基本上UI线程应该只处理UI,其他一切都应该在后台工作线程中完成,该线程发送一个在UI线程中捕获的信号,并且更新GUI的槽在UI线程中执行。
除了@ViktorKerkez和@Wilbur的答案之外,信号和插槽还提供了火灾和遗忘的通知系统,以及解耦类。
这样做的一个很大的好处是,一个类可以发出信号,而不知道接收消息的内容是什么。它可能只是一个连接了插槽的对象,也可能是几十个。或者,您可能需要一个具有一个插槽的单个类,该插槽连接到多个信号。因此它可以用作通知系统。
例如,想象一个程序,其中许多不同类型的对象将信息发送到日志。对象只是发出一个Log(文本)信号,而不关心实际记录的内容。这些信号可以连接到日志类,可以记录到文件,网络,屏幕或一次全部。记录对象不关心。
嗯......是的,你可以。但你需要更大的思考。在示例代码中,mouseReleaseEvent的调用者必须具有对接收通知的对象的引用,并显式调用适当的方法。使用插槽和信号机制将事件生成器(例如小部件)与事件使用者分离 - 几乎是任意的其他对象。这使得设置通信和控制流更容易,并且在低级UI组件外部,这是好事。它还使这些组件可以重复使用 - 通过在外部移动布线代码,我们使其独立于应用程序逻辑。