QT的核心之一是信号和插槽,信号和插槽实现使用类似的观察者模式。
在面向对象的编程中,将创建许多示例,每个实例都是独立的。如果每个实例可以合作合作,那么将会有一种机制在对象中传输消息。构造以在对象之间传输信息。
回调函数是功能指针。如果您希望处理功能通知某些事件,则需要将此指针传递给处理函数,并且处理功能在适当的时间调用回调函数。MFC是使用的回调函数,但是回调可能不直观,不容易理解,不能保证它是安全的。
从编程语言语法的角度来看,so称为对象之间的通信是函数调用的问题,但它只是某个对象的成员函数的成员函数。这更容易理解实现的原则信号和凹槽。
(1)几种形式的功能调用
回调函数的本质是基于“您希望其他人执行代码,并且无法移动他人的代码”的情况。回调函数是函数指针的用法。如果多个类需要注意特定类的变化,此时,您需要在类中维护列表以存储多个回调功能。对于每个相关的类,都需要类似的任务,因此此方法不是fixible.example回调函数:
QT开发了一种新的消息传输机制,以消除回调功能的缺点,即信号和凹槽。
顺便说一句,QT提供了一种可以自动有效地组织和管理QOBJEC ++ T的QT对象的机制。该机制是一种对象树。该机制在接口中很好地帮助程序员减轻内存泄漏问题。例如,当应用程序创建带有父窗口部分的对象时,将添加对象中的对象列表。当应用程序破坏父窗口部分时,将删除孩子的孩子的孩子的对象一个人。这使我们能够在编程,提高编程效率并确保系统稳定性时专注于系统的业务。因此,在New具有父窗口之后,只要可删除父窗口,它的子窗口就可以使用。将自动释放,并且释放顺序(即结构的顺序)与这些子对象的结构相反。
例如,当我们要求鼠标单击特定按钮时,需要关闭相应的窗口,然后此按钮将发送一个点击信号,并且在接收此信号后将执行窗口。然后,此信号是按钮要单击,凹槽是执行关闭功能的窗口。信号和插槽可以理解为“命令执行”,也就是说,信号是命令,并且凹槽正在执行命令。
当对象的内部状态更改时,如果其他对象需要响应其状态更改,此时应更改此类的信号。语句信号使用信号关键字。使用EMIT关键字符号信号。信号需要重点:
凹槽实际上是普通的C ++函数。它可以是虚拟函数,静态功能,也可以重新加载。它可以是公共,受保护和私人的。当然,它可以由其他C ++成员函数调用。信号连接。当发出连接到它的信号时,将调用插槽,并且插槽所在的类也需要直接或间接继承Qobject,然后添加q_object。需要实现凹槽函数,因为它是普通的C ++函数。
在QT4中,可以使用声明插槽:公共/私人插槽:
这些声明在QT5中不需要,每个函数都可以视为插槽函数,也可以将lambda表达式用作凹槽。但是,对于程序的可读性,应声明推荐的插槽函数。
使用连接函数,有两个原型。
原型1:
喜欢:
QT4和QT5都可以使用此连接方法。
原型2:
喜欢:
这是QT5的新连接方法,它允许拼写,参数检查,键入考试和支持在编译过程中兼容性参数的兼容性转换。
目前,凹槽的执行顺序与同一线程有关。同一线程和凹槽的执行顺序的序列与插槽的顺序有关。越过线程时,执行顺序不确定。
只要发送任何信号,该插槽就会被调用。
发送第一个信号时,发送了第二个信号。此外,此信号信号和信号沟的形式之间没有差异。
积极取消连接以使用Disconnect()函数。
支持QT 5支持Lambda表达式的编译器。
第五参数可以采用以下值,该值表示代表的含义如下:
QT :: AutoConnection默认值。使用此值,连接类型将确定何时发送信号。如果接收器和发件人在同一线程中,则自动使用QT :: DirectConnection类型。如果接收机和发件人不是线程,则QT:: QueuedConnection类型被自动使用。QT:: DirectConnection插槽函数在发送信号时将直接调用,并且凹槽函数和信号发送器在相同的线程中。效果似乎直接在信号处直接调用插槽函数发送位置。效果看起来像一个函数调用并同步执行。发出所有插槽函数后,发出的代码将执行。qt:: queueDconnection信号是发出的,该信号将临时放置在消息队列中,您需要等到获得接收对象的事件周期才能获得。QT :: BlockingQueuedConnection插槽函数与QT :: QueuedConnection一致,但是发送信号后发件人的线程在发送信号之后的线程直到插槽函数运行为止。并且接收器和发件人不得在线程中,否则该程序将被锁定。这可能是多线程之间的同步所必需的。qt:: UniqueConnection,该标志可以通过一点或(当多个信号为conne时插入一个插槽,有时您需要确定发送哪个对象。
现在让我们看看信号和凹槽是如何实现的吗?在这里,为了解释信号和凹槽的原理,以下是一个简单的信号和凹槽示例。代码如下显示:
定义类别信号和插槽,并在类中定义一个信号和插槽。
SIGNALSANDSLOTS.H文件
signalsandslots.cpp文件
main.cpp文件
出于错误的原因和解决方案,请参阅:在窗口系统下开发QT(9)-MOC文件的两种方法
MOC(Meta-Object编译器)MetoMoteric Pre-Compiler.MOC读取C ++标头文件。如果找到一个包含Q_Object Macro的索赔,它将生成一个包含这些类的元对象代码的C ++源文件,并将MOC_用作前缀。动态属性的信号和插槽机制,类型信息和动态属性系统需要META对象代码。必须编译MOC生成的C ++源文件并与类实现相关联。通常,MOC不是手动调用的,而是由构造系统自动调用的,因此它不需要程序员的其他工作。
让我们看一下q_object的真实面孔,其宏定义如下:
扩展其中的宏并删除无用的代码,如下所示:
您还可以在SignalSandSlots.h中替换上述代码。moc_signalsandslots.cpp一起编译在一起。否则,此类不完整。
打开生成的moc_signalsandslots.cpp文件以查看内部的代码。
从上面的代码中,我们了解到QT的Meta -Object System:信号插槽,属性系统和运行时的操作信息存储在静态对象staticmetaObject中。
接下来是其他三个公共接口的定义。您还可以直接调用代码中的以下功能:
接下来,我们发现标题文件中声明的信号是这里的真实定义,这就是为什么信号不要求我们定义它的原因。
说这是一个关键字并不准确。它实际上是宏。
如果信号扩展,则是公开的,因此所有信号都是公开的,您无需添加公共,受保护的,私人的有限符号,例如凹槽。
像信号一样,插槽只是没有有限的字符,因此是否可以通过对象调用它取决于需求。
它的宏定义:
发射是一个空的宏。当它被替换时,它等效于无效。该程序实际上是调用sigprint()函数,而不是从真实意义上发送信号。许多初学者认为,当发射时,QT会发送信号,这实际上是一个常见的函数调用。
通过上述代码和一餐,让我们总结信号和插槽的特定过程。
以上是信号凹槽的整个过程。通常,这是一种“注册指数”机制。没有发送系统信号的内容。
1.凹槽的属性
公共插槽:该区域中的插槽声明意味着所有对象都可以与它们连接信号。这对于组件编程非常有用。您可以创建对彼此不了解并连接其信号和凹槽的对象适用于这些凹槽,它们是实现的一部分,但是它们的界面接口面向外部。私人插槽:在该区域声明的插槽意味着只有类型可以将信号与它连接起来。这适用于非常接近的类别。
2.如果发射器和接收器属于同一对象,则可以省略连接调用中的接收器参数。
3.在三种情况下,可以使用disconnect()函数:(1)断开与某个对象关联的所有对象。实际上,当我们在某个对象中定义一个或多个信号时,这些信号与凹槽相关其他几个对象。如果我们想切断这些关联,我们可以使用此方法,这非常简洁。
(2)用特定的信号解散所有关联。
(3)打破两个对象之间的连接。
0在断开函数中可以用作传递符号,它代表所有信号中的所有凹槽函数,所有接收对象和接收对象。等于0。
4.定义不能在信号和插槽的参数中使用。由于MOC工具不扩展#Define,因此信号和插槽中携带参数的宏无法正常工作。
5.构造函数不能在信号或插槽声明区域中使用。
6.函数指针不能直接用作信号或插槽的参数。这是非法的。您可以一起使用并使用Typedef,如下所示:
7.信号和凹槽不能具有默认参数:因为信号和插槽绑定在运行时发生。
8.信号和凹槽无法携带模板参数
如果信号和插槽声明为模板参数,即使MOC工具没有报告错误,也无法获得预期结果,您也可以使用Typedef
9.嵌套类不能位于信号或插槽区域,也不能位于信号或插槽中,也就是说,B类B类,并且不可能在B类中声明信号和凹槽。
10. youyuan声明不能位于信号或插槽声明区域中。
有两种情况:1。如果每个信号都需要处理,则有两种方法可以解决该问题,也就是说,在信号和插槽的连接函数中指定第五个参数,或设置为封锁连接的连接可以很好地解决;2.如果您只需要处理最新的信号,则在此还提供了两个解决方案:A。信号的线程通过确定该布尔的状态以确定是否发送信号来确定信号的线程;B.凹槽执行已完成,信号中线程的返回值将发送tonew信号。
原始:https://juejin.cn/post/7096101380204527623