欢迎小伙伴的点评✨✨,相互学习、互关必回、全天在线
博主 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神
本章节会探讨三个开发步骤、如下所示:
Qt 提供了信号和槽机制用于完成界面操作的响应,信号和槽机制是完成任意两个 Qt 对象之
间的通信机制。其中,信号会在某个特定情况或动作下被触发,槽是等同于接收并处理信号的函
数。例如,若要将一个窗口部件的变化情况通知给另 一个窗口部件,则一个窗口部件发送信号,
另一个窗口部件的槽接收此信号并进行相应的操作,即可实现两个窗口部件之间的通信 。 每个 Qt
对象都包含若干个预定义的信号和若干个预定义的槽 。 当某一个特定事件发生时,一个信号被发
送,与信号相关联的槽则会响应信号并完成相应的处理 。 当 一个类被继承时,该类的信号和槽也
同时被继承,也可以根据需要自定义信号和槽 。
(1)一个信号可以与另一个信号相连,代码如下:
connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal1));
表示Object1的信号1发送可以触发Object2的信号1发送
(2)同一个信号可以与多个槽相连,代码如下:
connect(Object1,SIGNAL(signal2),Object2,SIGNAL(slot2));
connect(Object1,SIGNAL(signal2),Object3,SIGNAL(slot1));
(3)同一个槽可以相应多个信号,代码如下:
connect(Object1,SIGNAL(signal2),Object2,SIGNAL(slot2));
connect(Object3,SIGNAL(signal2),Object2,SIGNAL(slot2));
但是,常用的连接方式为:
connect(Object1,SIGNAL(signal),Object2,SLOT(slot));
其中, signal 为对象 Objectl 的信号, slot 为对象 Object2 的槽。
(4)信号与槽机制的SIGNAL()和SLOT()解析:
SIGNAL()和 SLOT()是 Qt 定义的两个宏,它们返回其参数的 C 语言风格的字符串 (const
char*) 。因此,下面关联信号和槽的两个语句是等同的:
connect(button,SIGNAL(clicked()), this, SLOT (showArea ()));
connect (button, "clicked()",this, "showArea() ");
(1) 类型安全。
需要关联的信号和槽的签名必须是等同的,即信号的参数类型和参数个数
与接收该信号的槽的参数类型和参数个数相同。不过,一个槽的参数个数是可以少千信号的参
数个数的,但缺少的参数必须是信号参数的最后一个或几个参数。如果信号和槽的签名不符,
编译器就会报错。
(2)松散耦合。
信号和槽机制减弱了 Qt 对象的耦合度。激发信号的 Qt 对象无须知道是哪
个对象的哪个槽需要接收它发出的信号,它只需做的是在适当的时间发送适当的信号就可以了,
而不需要知道也不关心它的信号有没有被接收到,更不需要知道是哪个对象的哪个槽接收到了
信号。同样,对象的槽也不知道是哪些信号关联了自己,而一旦关联信号和槽, Qt 就保证了适
合的槽得到了调用。即使关联的对象在运行时被删除,应用程序也不会崩溃。
一个类若要支待信号和槽,就必须从 QObject 或 QObject 的子类继承。注意, Qt 信号和槽
机制不支持对模板的使用。
信号和槽机制增强了对象间通信的灵活性,然而,这也损失了一些性能。同回调函数相比,
信号和槽机制运行速度有些慢。通常,通过传递一个信号来调用槽函数会比直接调用非虚函数
的运行速度慢 10 倍。主要原因如下。
(1) 需要定位接收信号的对象。
(2)安全地遍历所有的关联(如一个信号关联多个槽的情况)。
(3)编组(marshal)/解组(unmarshal)传递的参数。
(4)在多线程时,信号可能需要排队等待。
然而,与创建堆对象的 new 操作及删除堆对象的 delete 操作相比,信号和槽的运行代价
很小。信号和槽机制导致的这点性能损失对实时应用程序是可以忽略的;同信号和槽提供的
灵活性和简便性相比,这点性能损失也是值得的。
QtS 元对象系统提供了对象间的通信机制(信号和槽)、运行时类型信息和动态属性
系统的支待,是标准 C++的一个扩展,它使 Qt 能够更好地实现 GUI 图形用户界面编程。
QtS 的元对象系统不支持 C++模板,尽管该模板扩展了标准 C++ 的功能。但是,元对象
系统提供了模板无法提供的一些特性。 QtS 元对象系统基千以下三个事实。
(1)基类QObject:
任何需要使用元对象系统功能的类必须继承自QObject
(2)Q_OBJECT宏:
Q_OBJECT 宏必须出现在类的私有声明区中,用千启动元对象的特性。
(3)元对象编译器(Meta-Object Compiler,moc):
为QObject 子类实现元对象特性提供必要的代码实现。
在设计较复杂的 GUI 用户界面时,仅通过指定窗口部件的父子关系以期达到加载和排列窗
口部件的方法是行不通的,最好的办法是使用 Qt 提供的布局管理器。
QGridLayout *mainLayout=new QGridLayout(this); //(a)
mainLayout->addWidget(label1,0,0); //(b)
mainLayout->addWidget(lineEdit,0,1);
mainLayout->addWidget(label2,1,0);
mainLayout->addWidget(button,1,1);
setLayout(mainLayout); //(c)
其中,
(a)QGridLayout *mainLayout=new QGridLayout(this): 创建一个网格布局管理器对象mainLayout, 并用 this 指出父窗口。
(b) mainLayout->addWidget(…):分别将控件对象 labell 、 lineEdit 、 label2 和 button 放置在布局管理器中,还可以在创建布局管理器对象时不必指明父窗口。
(c) QWidget:":setLayout(…):将布局管理器添加到对应的窗口部件对象中。因为这里的主窗口就是父窗口,所以直接调用 setLayout(mainLayout)即可。
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QPushButton *button; //声明一个QPushButton类型的指针
QLineEdit *LineEdit; //声明一个QLineEdit类型的指针
private slots:
void button_on(); //声明一个函数用于:button按钮触发连接用的槽
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
button = new QPushButton("信号与槽"); //初始化button指针,分配空间
LineEdit = new QLineEdit; //初始化LineEdit指针,分配空间
connect(button,SIGNAL(clicked(bool)),this,SLOT(button_on())); //用于连接按钮信号与槽的触发
QGridLayout *mainLayout = new QGridLayout; //声明一个QGridLayout类型,并分配空间,用于画图
mainLayout->addWidget(button,2,0); //用画图指针设计按钮在窗口中的位置
mainLayout->addWidget(LineEdit,1,0);
setLayout(mainLayout);
}
Widget::~Widget()
{
delete ui;
}
void Widget::button_on()
{
LineEdit->setText("信号与槽连接成功");
qDebug()<<1;
}