我很难理解Qt中信号和事件的区别,能有人解释一下吗?
事件是一个封装在类中(QEvent
)的消息,它在事件循环中被处理并分派给一个接收者,该接收者可以接受该消息或将其传递给其他人处理。通常情况下,它们是响应于鼠标点击等外部系统事件而创建的。
信号和槽是一种方便的方法,用于让QObject
之间进行通信,与回调函数更相似。在大多数情况下,当“信号”被发射时,任何连接到它的槽函数都会直接被调用。唯一的例外是当信号和槽跨越线程边界时,在这种情况下,信号将被转换为一个事件。
事件是发生在对象“内部”或“外部”的事情。通常,您可以在对象自身的类代码中处理它们。
信号由对象“发射”出来。该对象基本上是通知其他对象发生了某些事情。其他对象可能会因此执行某些操作,也可能不会,但这并不是发射器的职责。
我对两者的区别印象如下:
假设你有一个服务器设备,运行着一个无限循环,监听一些外部客户端事件,然后通过执行一些代码来响应这些事件。(它可以是一个CPU,监听来自设备的中断;或者是客户端JavaScript浏览器代码,监听用户点击;又或者是服务器端网站代码,监听用户请求网页或数据)。
或者它可以是你的Qt应用程序,运行着它的主要循环。
我将解释以下两个主要区别,尽管第二个区别有些争议:
事件是低级消息,从客户端传递给您。事件类型是一个严格有限的集合(~20个不同的事件类型),由硬件决定(例如,鼠标单击/双击/按下/释放、鼠标移动、键盘键按下/释放/按住等),并在应用程序和用户之间的交互协议(例如,X协议)中指定。
例如,当X协议被创建时,没有多点触控手势,只有鼠标和键盘,所以X协议不会理解您的手势并将它们发送到应用程序,它只会将其解释为鼠标单击。因此,随着时间的推移,引入了X协议的扩展。
X事件对Widget一无所知,Widget仅存在于Qt中。 X事件仅知道X窗口,它们是您的Widget基本矩形组成的,您的Qt事件只是一个薄包装,提供了不同操作系统本地事件之间的兼容层,以方便Widget级别逻辑层作者。
Widget级别逻辑处理信号,因为它们包含您操作的Widget级别含义。此外,一个信号可以由不同的事件触发,例如单击“保存”菜单按钮或键盘快捷键,如Ctrl-S。
假设您有一个函数foo(),该函数可以触发信号或发出事件。 如果它触发了信号,信号将在调用该函数的线程中执行,紧接着该函数执行。
另一方面,如果它发出了事件,事件将被发送到主循环,并且它取决于主循环何时将该事件传递给接收端以及接下来会发生什么。
因此,两个连续事件甚至可能以相反的顺序交付,而连续触发的两个信号仍然是连续的。
尽管术语并不严格,但Unix中作为进程间通信手段的“信号”更应该被称为事件,因为它们是异步的:您在一个进程中调用一个信号,却永远不知道事件循环何时会切换到接收进程并执行信号处理程序。
P.S. 如果我的一些示例在字面上不完全正确,请原谅我。它们在精神层面上仍然不错。
事件直接传递给类的事件处理程序方法。它们可以在您的子类中重载,选择不同的方式来处理事件。事件也会从子级传递到父级,直到有人处理它或者它掉下去。
另一方面,信号是公开发出的,任何其他实体都可以选择连接并监听它们。它们通过事件循环传递,并在队列中被处理(如果它们在同一线程中,则也可以直接处理)。