目录
2. QT程序的运行框架
2.4 设计界面元素的行为:信号、槽函数、对象之间的通信
2.4.1 对象之间的通信
2.4.2 信号槽与消息队里区别
2.4.3 预定义信号与默认槽函数
2.4.4 预定义信号与默认槽函数:案例2
2.4.5 预定义信号与自定义槽函数:案例3
2.5 界面的切换:隐藏与显示
2.6 界面的关闭
2. QT程序的运行框架
2.4 设计界面元素的行为:信号、槽函数、对象之间的通信
2.4.1 对象之间的通信
mx:信号、消息
hx:回调的函数指针
obj_x:发送信号和回调函数对应的对象
当对象收到某个事件后,就会查自己内部的事件处理链表,并调用特定对象的成员函数,完成对对象的时间的处理。
在Qt中,槽函数是用于接收信号并执行相应操作的函数。当某个特定事件发生时,例如按钮被点击、文本框内容改变等,与之相关联的信号将被发射。槽函数会在接收到信号时被调用,用于执行相应的逻辑。
以下是使用槽函数的一般步骤:
-
在头文件中声明槽函数:在你的类的头文件中声明槽函数。槽函数可以是公有的、私有的或保护的函数。
class MyClass : public QObject { Q_OBJECT public slots: void mySlot(); // 声明槽函数 };
-
在源文件中实现槽函数:在类的源文件中实现槽函数的具体逻辑。
void MyClass::mySlot() { // 槽函数的具体逻辑 }
-
将槽函数与信号关联:使用
connect
函数将槽函数与信号进行关联。这样当信号被发射时,槽函数将被调用。MyClass obj; QObject::connect(sender, SIGNAL(someSignal()), &obj, SLOT(mySlot()));
在上述代码中,
sender
是发送信号的对象,someSignal
是发送信号的信号名,obj
是接收槽函数的对象,mySlot
是槽函数的名称。connect
函数用于建立信号和槽之间的连接。
注意:
- 在使用槽函数的类中,需要将
Q_OBJECT
宏加入类的声明中。该宏用于启用Qt的元对象系统,以便支持信号和槽的运行机制。 - 多个信号可以与同一个槽函数进行连接,也可以一个信号连接到多个槽函数。
- Qt还提供了一些内置的信号和槽,例如按钮的
clicked()
信号,用于处理按钮点击事件。 - 槽函数可以有不同数量和类型的参数,但是槽函数的参数必须与信号的参数一致,或者可以自动转换为信号参数类型。
- 槽函数可以是普通的成员函数,也可以是静态函数。
通过使用槽函数,你可以非常方便地响应并处理Qt应用程序中发生的各种事件与交互动作。
在Qt中,emit
关键字用于在发送对象中发射(触发)一个信号。当你在某个类中使用emit
关键字时,将调用与之相关联的信号的所有接收对象的槽函数。也就是说,某个接收对象的槽函数是由发送信号的对象,通过rev_obj.slot_function()来实现的。这与消息队列机制是不同的,消息队列机制是由接收方线程检查消息ID, 并根据消息ID来执行接收方的内部函数。
QT中信号+槽函数,类似回调函数的注册和回调,当发送方发送某个信号时,相当于QT框架会检查接收对象关心某个信号的所有接收对象,并调用其先前通过connnect注册的回调函数!!!
在发射信号的过程中,以下是emit
的原理:
-
信号与槽函数的连接:在信号接收对象的代码中使用
connect()
函数将信号与接收对象自身的一个或多个槽函数进行连接。这个连接关系通常在对象的构造函数中建立。当信号发射时,与之连接的槽函数将被调用。 -
信号的声明和定义:在类的声明中,信号被声明为
signals
部分。信号的定义包含了信号的名称、参数列表和可能的返回类型。信号的定义告诉Qt元对象系统如何生成信号的运行时代码。 -
元对象系统:在编译阶段,Qt的元对象系统会扫描类的声明和定义以生成相关的运行时代码,其中包括信号和槽函数的相关信息。
-
运行时发射信号:当使用
emit
关键字发射信号时,Qt运行时库会检查接收信号的元对象,确定与之相关联的槽函数,并依次调用这些槽函数(在发送对象的线程上下文中调用接收对象的槽函数!!!!,而不是在接收对象的线程的上下文执行槽函数)。
总而言之,emit
关键字实际上是一个宏,通过元对象系统和信号与槽的连接关系,实现了信号的发射和与之相关联的槽函数的调用。这种设计方式使得Qt中的信号与槽机制成为可能,并提供了一种灵活的方式来处理对象间的通信与交互。
connect
函数是Qt中用于建立信号和槽之间连接的方法。通过connect
函数,你可以将一个信号与一个或多个槽函数进行关联,以实现对象间的通信。
connect
函数有不同的重载形式,常见的形式包括:
-
基本形式:
connect(sender, SIGNAL(signal), receiver, SLOT(slot))
sender
:发送信号的对象的指针或对象名。SIGNAL(signal)
:要连接的信号的名称,可以使用宏SIGNAL()
将信号名称转换为字符串。receiver
:接收信号的对象的指针或对象名。SLOT(slot)
:要连接的槽函数的名称,可以使用宏SLOT()
将槽函数名称转换为字符串。
-
Lambda表达式形式:
connect(sender, &Sender::signal, receiver, [=](参数列表) { ... })
&Sender::signal
:要连接的信号的指针,使用&操作符获取信号的指针。receiver
:接收信号的对象的指针或对象名。=
:传递捕获方式,用于在Lambda表达式中使用当前作用域的变量。(参数列表)
:指定Lambda表达式的参数列表。{ ... }
:Lambda表达式的具体实现。
connect
函数的返回值是一个bool
类型,用于表示连接是否成功。如果连接成功,返回true
;如果连接失败,返回false
。
在使用connect
函数时,需要注意以下几点:
- 在连接信号和槽之前,确保相关的类已经通过
Q_OBJECT
宏进行声明,以启用Qt的元对象系统支持。 - 信号和槽必须具有相同的参数列表,或者可以通过自动类型转换进行匹配。
- 一次连接可以将一个信号连接到一个或多个槽函数,也可以将多个信号连接到一个槽函数。
- 在断开连接之前,可以使用
disconnect
函数来取消信号和槽之间的连接。
通过connect
函数,你可以实现Qt中强大的信号和槽机制,用于处理对象间的通信和交互。
这种机制使得Qt编程更加灵活和可扩展,提高了代码的可维护性和重用性。
2.4.2 信号槽与消息队里区别
信号槽机制和消息队列是两种不同的通信机制,它们在实现方式和使用场景上有所区别。
信号槽机制是Qt中特有的事件驱动的通信机制,用于在对象之间进行异步的、直接的通信。它通过信号的发射和槽函数的调用实现对象之间的通信。一个对象可以发射一个信号,而其他对象可以连接到该信号并响应它,即调用与之关联的槽函数。信号槽机制适用于多个对象之间的实时交互和事件驱动的场景,提供了一种低耦合、高度灵活的通信方式。信号槽本质是注册回调机制!!!用于线程内部的不同对象之间通信或线程间不同对象之间的通信,信号对应的槽函数是在发送信号一端执行的!!!
消息队列是一种更通用的通信机制,可以用于不同类型的应用程序和系统之间的通信。在消息队列中,消息是实体的载体,可以包含任意类型的数据。消息生产者将消息发送到队列,并将其放入接收队列中,而消息消费者从队列中获取和处理消息。消息队列通常用于解耦和异步通信,可以在不同的线程、进程甚至不同的计算机之间传递消息。消息队列适用于大型系统、分布式系统和并发编程中。消息id对应的处理函数是在消息的接收端执行的!!!
总结一下,信号槽机制是Qt特有的、用于对象之间的事件驱动通信的机制,而消息队列是一种通用的通信机制,可用于不同类型的应用程序和系统之间的异步通信。根据具体的应用场景和需求,选择合适的通信机制来达到预期的目标。
2.4.3 预定义信号与默认槽函数
默认的槽函数:被定义在主窗口对象中,而不是控件对象中。
预定义信号:由主窗口对象的控件对象发送。
ConnectSlotsBySlotsName
是一种辅助函数,用于在Qt中根据槽函数名称进行信号和槽的连接。
在Qt中,一般使用connect
函数来建立信号和槽的连接。它是一种常用的方式,可以根据信号和槽的指针进行连接。
而ConnectSlotsBySlotsName
函数则提供了另一种方式,通过槽函数的名称来建立信号和槽的连接。它适用于一些特定的场景,比如在运行时动态地建立信号和槽的连接。
使用ConnectSlotsBySlotsName
函数时,你需要将一个发送信号的对象、一个接收信号的对象以及槽函数的名称作为参数传入该函数。该函数会在接收信号的对象中查找对应名称的槽函数,并将其与信号进行连接。
下面是一个使用ConnectSlotsBySlotsName
的简单示例:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(ReceiveSlot()));
在上述代码中,ConnectSlotsBySlotsName
函数会在receiver
对象中查找名为ReceiveSlot
的槽函数,并将其与sender
对象发射的名为signal
的信号进行连接。
请注意,ConnectSlotsBySlotsName
函数是一个由第三方提供的辅助函数,它不是Qt官方库中的一部分。如果你需要使用该函数,请确保你已经在项目中包含了相应的辅助库,并了解其详细的使用方法和限制。
对于默认槽函数,每个发送信号的控件对象,根据控件自身名字+信号的名字,到控件的父窗口中寻找对应的槽函数!!!
在 Qt 中,有一些默认的槽函数可以用于处理常见的事件和信号。这些默认的槽函数是编写 Qt 应用程序时常用的功能。
以下是一些常见的默认槽函数的示例:
on_<objectName>_<signalName>()
:这是一种常见的命名约定,用于处理来自特定对象的特定信号。比如,当一个按钮的点击事件被触发时,可以定义一个形如on_pushButton_clicked()
的函数来处理该事件。on_<objectName>_clicked()
:用于处理特定对象的点击事件,如按钮的点击事件。例如,当一个名为myButton
的按钮被点击时,可以定义一个名为on_myButton_clicked()
的函数来处理点击事件。on_<objectName>_activated(<args>)
:用于处理特定对象的激活事件,如下拉框的选择事件。例如,当一个名为myComboBox
的下拉框的选择发生变化时,可以定义一个名为on_myComboBox_activated(<args>)
的函数来处理选择事件。on_<objectName>_textChanged(const QString &text)
:用于处理特定对象的文本变化事件,如文本框的内容改变事件。例如,当一个名为myLineEdit
的文本框的文本内容改变时,可以定义一个名为on_myLineEdit_textChanged(const QString &text)
的函数来处理文本变化事件。
请注意,以上命名约定不是 Qt 的强制要求,只是一种常见的约定,用于方便识别和管理槽函数。
当然,你也可以根据需要自定义槽函数的名称和参数,以满足特定的需求。
Qt 提供了许多预定义的信号,这些信号是 Qt 类中定义的一些常用事件或状态变化的信号。这些预定义信号可以用于连接到对应的槽函数,以实现特定的功能或响应特定的事件。
以下是一些常见的 Qt 预定义信号的示例:
clicked()
:当一个按钮被点击时发出的信号。pressed()
:当按钮被按下时发出的信号。released()
:当按钮被释放时发出的信号。textChanged(const QString &text)
:当文本框中的文本发生改变时发出的信号,同时传递新的文本内容。currentIndexChanged(int index)
:当下拉框或列表框中当前选中项发生改变时发出的信号,同时传递新选中项的索引。stateChanged(int state)
:当复选框或单选按钮的状态发生改变时发出的信号,同时传递新的状态,其中 0 表示未选中,1 表示选中。objectNameChanged(const QString &objectName)
:当对象的名称发生改变时发出的信号,同时传递新的对象名称。
这些只是一些常见的预定义信号示例,实际上 Qt 提供了更多的预定义信号,可以根据具体的需要去查看 Qt 类对应的文档以了解更多细节。同时,你也可以自定义信号以满足特定的需求。
由主窗口的槽函数接收子控件的信号!!!即事件的发送者是子控件,槽函数的调用者是子控件。槽函数的定义者、接收者、实现者实际是主窗口对象!!!
实际上,与定义槽函数可以定义在任何其他控件对象,也就是说,任意控件对象也可以直接接收其他控件的事件,而不需要通过主窗口对象!!!,即并不需要把信号处理的槽函数定义在主窗口对象中,也可以定义在某个控件对象中,此时,就不需要使用connect进行对象和槽函数的关联!!!
2.4.4 预定义信号与默认槽函数:案例2
2.4.5 预定义信号与自定义槽函数:案例3
在上图中,timer_1s->start(1000)调用开始,就进行计数,当计数满一秒时, timer_1s自动产生并发送一个事件:time_out()。
2.5 界面的切换:隐藏与显示
2.6 界面的关闭
备注:
通过this->next把相互独立的窗体给串联起来。