Qt信号和槽

GUI 程序除了要绘制控件,还要响应系统和用户事件,例如重绘、绘制完成、点击鼠标、敲击键盘等。当事件发生时,UI 会产生相应的变化,让用户直观地看到。

大部分编程(例如Win SDK、Web前端)中使用回调函数来响应事件,而 Qt 却独创了信号和槽机制。

所谓回调函数,就是程序员提前定义一个函数,当事件发生时就调用该函数。

信号和槽是 Qt 的核心,它让两个互不相干的对象连接起来,当一个对象的状态改变时,可以通知另一个对象。

我们先通过例子来演示一下信号和槽:

新建一个Qt应用程序

注意,最后一定要选择去掉“创建界面”复选框。

在main.cpp中添加代码:

源代码如下:

#include "mainwindow.h"
#include <QApplication>
#include <QMainWindow>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>

int main(int argc, char *argv[])
{
       QApplication app(argc, argv);
       QMainWindow w;
       w.setWindowTitle("Widgets工程");
       w.resize(325, 120);
       QLineEdit lineEdit(&w);
       lineEdit.setGeometry(30, 20, 180, 36);
       lineEdit.setPlaceholderText("请输入文本");
       QPushButton btn("取消", &w);
       btn.setGeometry(220, 20, 70, 36);
       QLabel label(&w);
       label.setGeometry(35, 60, 250, 30);
       //连接clicke()信号和quit()槽
       QObject::connect(&btn, SIGNAL(clicked()), &app, SLOT(quit()));
       //连接textChanged()信号和setText()槽
       QObject::connect(&lineEdit, SIGNAL(textChanged(QString)), &label, SLOT(setText(QString)));
       w.show();
       return app.exec();
}

该代码中创建了三个控件,一个文本输入框(LineEdit)、一个按钮(PushButton)和一个Label,他们都是主窗口 w 的子对象。

运行结果:

点击“取消”按钮,程序就关闭了,这是第25行代码的作用;在文本输入框中输入一段文本,下面的 Label 会随时显示出来,这是第27行代码的作用。

先关注第25行代码。clicked() 是按钮 btn 的信号,quit() 是 app 的槽,connect() 函数将它们连接起来,就像“楔子”插入“凹槽”中。用户点击按钮时会发出 clicked() 信号,然后由 quit() 槽接收并关闭程序。

信号是只有函数声明、没有函数体的成员函数。槽是拥有完整函数体的普通成员函数,你可以在槽函数中实现各种功能,与普通函数相比并没有区别,例如 quit() 的作用就是退出程序。

connect() 是 QObject 类的静态成员函数;QObject 是 Qt 中所有类的基类,它就像“树根”,从这里派生出了所有其他“树枝”。

需要注意的是,信号不是事件。当用户点击“取消”按钮时,Qt 会捕获该点击事件,进行预处理,然后发射 clicked() 信号; clicked() 和 quit() 关联起来了,接下来就会调用 quit() 函数。

信号和槽机制归根结底也是回调函数,只不过绕了个圈子。在这种机制下,程序员有两次处理事件的机会:

一是在捕获事件后发射信号前进行预处理(事件不符合预期可以不发射信号)。

二是在槽函数中进行主要处理。

再来看第27行。textChange() 信号会在文本改变时发出,setText() 槽用来设置 Label 的文本,QString 是要传递的数据的类型。

当用户输入文本时,lineEdit 会发出 textChange() 信号,该信号将携带数据,数据类型为 QString,数据内容为输入的文本;

setText() 槽接收到信号后先解析信号携带的数据,获取用户输入的文本,然后填充到 Label 中。

关于 connect()

connect() 是 QObject 类的静态成员函数,它有多个原型:

connect(QObject *sender,   char *signal,  QObject *receiver, char *method);

connect(QObject *sender,   PointerToMemberFunction signal, QObject *receiver, PointerToMemberFunction method);

connect(QObject *sender,   PointerToMemberFunction signal, QObject *context,  Functor functor);

connect(QObject *sender,   QMetaMethod &signal, QObject *receiver, QMetaMethod &method);

connect(QObject *sender,   PointerToMemberFunction signal,  Functor functor);

简单起见,上面省略了 connect() 的返回值和最后一个参数,以及某些参数前面的 const 修饰符,读者可以在 Qt 帮助手册中查看完整的原型。

connect() 函数返回值类型为QMetaObject::Connection,表示当前连接句柄。

最后一个参数为Qt::ConnectionType type = Qt::AutoConnection,表示连接类型,一般默认即可。

观察上面的原型,除了最后一个有3个参数,其他都有4个参数,其中:

1) sender 为信号发送者,receiver 为信号接收者,它们都是对象指针。

2) 第1个原型中,signal 为信号,method 为槽函数,它们都是字符串,必须借助 SIGNAL() 和 SLOT() 将函数形式转换为字符串形式。

SIGNAL() 和 SLOT() 是宏,而非函数。上面的示例中就使用了该原型,它是常用的原型,初学者必须要掌握。

3) 第2个原型中,PointerToMemberFunction 为指向成员函数的指针。你可以将示例中的代码做如下更改:

QObject::connect(&btn, &QPushButton::clicked, &app, &QApplication::quit);

QObject::connect(&lineEdit, &QLineEdit::textChanged, &label, &QLabel::setText);

这是 Qt 5 新增的原型,可以在编译期间进行检查,如果信号和槽不存在或者不匹配,则会报错。

而第1种原型是从 Qt 诞生以来一直支持的,不能在编译期进行检测,如果信号和槽有误,只会在程序运行期间给出警告并返回 false,不容易发现问题,这是它的一个缺陷。所以在 Qt 5 中我们鼓励使用第2种原型。

时间: 2024-08-06 11:56:30

Qt信号和槽的相关文章

QT开发(十三)——QT信号与槽机制

QT开发(十三)--QT信号与槽机制 一.QT消息模型 QT封装了具体操作系统的消息机制,遵循经典的GUI消息驱动事件模型. QT定义了与操作系统消息相关的自己的概念,即信号与槽. 信号signal是由操作系统产生的消息. 槽slot是程序中的消息处理函数. connect将系统消息绑定到消息处理函数. 信号到槽的连接必须发生在两个QT对象间. bool QObject::connect ( const QObject * sender, //发生对象 const char * signal,

QT 信号与槽connect

QT 信号与槽connect QT 信号与槽connect connect函数调用几个限制 connect函数代码 QT中信号与槽的连接使用的connect函数是一个静态函数,在类QObject中定义.这里说的是QT5环境下.更详细的介绍可以看这里http://www.devbean.net/2012/12/how-qt-signals-and-slots-work-qt5/ connect函数调用几个限制 1. 信号的发送者必须是QObject的派生类对象.不然会出现error: invali

【C/C++学院】(13)QT开发技术/QT 基础/QT 信号和槽

Qt是一个跨平台的c++图形用户界面用用程序框架. Qt安装说明: windows下环境变量path需要加入以下路径,以便QT写的程序可以离开QT开发环境独立运行 C:\Qt\Qt5.2.0\5.2.0\mingw48_32\bin\;C:\Qt\Qt5.2.0\Tools\mingw48_32\bin; linux下需要设置.bash_profile文件 PATH中加入/opt/Qt5.2.0/5.2.0/gcc/bin 用root用户登录系统,进入/usr/lib目录后执行 ln libGL

Qt信号与槽自动关联机制

参考链接1:http://blog.csdn.net/skyhawk452/article/details/6121407 参考链接2:http://blog.csdn.net/memory_exception/article/details/50953005 信号与槽可以通过使用手写代码显式的实现关联 ,也可以运用 QMetaObject 类规定的槽 函数命名范式来实现自动关联. 显示关联 class MyWidget : public QWidget { Q_OBJECT public: M

Qt信号和槽的个人总结

1.connect [cpp] view plaincopy connect(sender,SIGNAL(signal()),receiver,SLOT(slot())); 这里用到了两个宏:SIGNAL() 和SLOT():通过connect声明可以知道这两个宏最后倒是得到一个const char*类型.在qobjectdefs.h中可以看到SIGNAL() 和SLOT()的宏定义: [cpp] view plaincopy #ifndef QT_NO_DEBUG # define QLOCA

关于Qt信号与槽机制的传递方向性研究(结论其实是错误的,但是可以看看分析过程)

最近由于项目的需求,一直在研究Qt.信号与槽机制是Qt的一大特色,该机制允许两者间传递参数,依次来实现对象间的通信.这个参数会分别存在于信号的参数列表和槽函数的参数列表中.需要注意的是,若将槽函数绑定至信号,槽函数的参数列表元素数目只能少于等于信号的参数列表元素数目.而且顺序和类型不能改变.至于缺少的参数应从信号参数尾部开始缺少. 突然今天想起来一个问题,如果一个对象发出信号,将内部的一个成员变量(非简单类型)作为参数向外发送,槽函数就可以接收到这个对象,那么槽函数是否可以完全操作这个对象呢?如

QT 信号和槽链接时注意事项

1.需要继承Qobject . 2.需要有Q_OBJECT宏. 3.如果有多重的继承关系,则每个子类都需要单独写Q_OBJECT宏,不能因为父类有Q_OBJECT宏就省略. 4.继承Qobject的类的声明必须在.h文件中,否则无法产生moc文件,信号和槽的链接就不起作用. 1 class myClass : public QObject 2 { 3 Q_OBJECT 4 public: 5 myClass(){} 6 } 5.信号和槽的链接用 connect函数. //!旧链接方式 编译时不检

Qt信号与槽应用实例一

..... connect(m_pGlobelWidget,signal(globeControlClick(object,object)),this,slot(globeControlClick(object,object))) ... signal中是m_pGlobelWidget本身具有的,qt中定义了此信号(有点类似MFC的消息)的触发规则 slot中是响应此信号的槽(对应MFC中的回调函数) 个人认为,Qt作为一种工具只需要在使用学习即可,也没有必要使用比较高大上的UI技术,此工具容易

QT信号与槽机制需要注意的问题

1.信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失.当然这种损失相对来说是比较小的,但是要追求高效率的话,比如实时系统,就要尽可能避免. 2.信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也可能产生死循环.因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发送所接收到的同样信号,防止死循环. 3.如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的. 4.宏定义不能用在si