Qt 普通函数和槽函数区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt 普通函数和槽函数区别相关的知识,希望对你有一定的参考价值。

QT是一个跨平台的C++ GUI应用构架,它提供了丰富的窗口部件集,具有面向对象、易于扩展、真正的组件编程等特点,更为引人注目的是目前Linux上最为流行的KDE桌面环境就是建立在QT库的基础之上。QT支持下列平台:MS/WINDOWS-95、98、NT和2000;UNIX/X11-Linux、Sun Solaris、HP-UX、Digital Unix、IBM AIX、SGI IRIX;EMBEDDED-支持framebuffer的Linux平台。伴随着KDE的快速发展和普及,QT很可能成为Linux窗口平台上进行软件开发时的GUI首选。

概述
信号和槽机制是QT的核心机制,要精通QT编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是QT的核心特性,也是QT区别于其它工具包的重要地方。信号和槽是QT自行定义的一种通信机制,它独立于标准的C/C++语言,因此要正确的处理信号和槽,必须借助一个称为moc(Meta Object Compiler)的QT工具,该工具是一个C++预处理程序,它为高层次的事件处理自动生成所需要的附加代码。
在我们所熟知的很多GUI工具包中,窗口小部件(widget)都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在QT中信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。 信号和槽能携带任意数量和任意类型的参数,他们是类型完全安全的,不会像回调函数那样产生core dumps。
所有从QObject或其子类(例如Qwidget)派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射(emit)出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。
你可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至于将一个信号与另外一个信号相连接也是可能的,这时无论第一个信号什么时候发射系统都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件编程机制。
信号和槽是类型安全的(签名相符的),即信号和槽的参数类型个数必须相同,或者槽的参数的个数可以少于信号的参数个数,但缺少的参数必须是信号参数的最后一个或几个参数。
参考技术A 可以接受信号,其他的没有区别.
在qt5中,将会没有区别,普通函数就可以作为槽函数.本回答被提问者和网友采纳
参考技术B 槽函数(Public Slots)与普通函数(Public Functions)的其实区别很模糊了
只要能对信号做出响应的函数都可以被称为槽函数
参考技术C 实现上Qt5以后没有啥区别了;但本质上是一种语用的区别,明确界定一下函数划分还是比较好,免得乱了。

Qt信号和槽

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

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

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


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

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

新建一个Qt应用程序

技术分享


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

技术分享


在main.cpp中添加代码:

技术分享


源代码如下:

  1. #include "mainwindow.h"  
  2. #include <QApplication>  
  3. #include <QMainWindow>  
  4. #include <QLabel>  
  5. #include <QPushButton>  
  6. #include <QLineEdit>  
  7.   
  8. int main(int argc, char *argv[])  
  9. {  
  10.        QApplication app(argc, argv);  
  11.        QMainWindow w;  
  12.        w.setWindowTitle("Widgets工程");  
  13.        w.resize(325, 120);  
  14.        QLineEdit lineEdit(&w);  
  15.        lineEdit.setGeometry(30, 20, 180, 36);  
  16.        lineEdit.setPlaceholderText("请输入文本");  
  17.        QPushButton btn("取消", &w);  
  18.        btn.setGeometry(220, 20, 70, 36);  
  19.        QLabel label(&w);  
  20.        label.setGeometry(35, 60, 250, 30);  
  21.        //连接clicke()信号和quit()槽  
  22.        QObject::connect(&btn, SIGNAL(clicked()), &app, SLOT(quit()));  
  23.        //连接textChanged()信号和setText()槽  
  24.        QObject::connect(&lineEdit, SIGNAL(textChanged(QString)), &label, SLOT(setText(QString)));  
  25.        w.show();  
  26.        return app.exec();  
  27. }  


该代码中创建了三个控件,一个文本输入框(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 类的静态成员函数,它有多个原型:

  1. connect(QObject *sender,   char *signal,  QObject *receiver, char *method);  
  2.   
  3. connect(QObject *sender,   PointerToMemberFunction signal, QObject *receiver, PointerToMemberFunction method);  
  4.   
  5. connect(QObject *sender,   PointerToMemberFunction signal, QObject *context,  Functor functor);  
  6.   
  7. connect(QObject *sender,   QMetaMethod &signal, QObject *receiver, QMetaMethod &method);  
  8.   
  9. 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种原型。






































以上是关于Qt 普通函数和槽函数区别的主要内容,如果未能解决你的问题,请参考以下文章

QT学习之信号和槽

qt自定义信号和槽函数 emit

Qt信号和槽

Qt信号与槽函数问题

QT的信号和槽

在 qt C++ 信号和槽中使用已删除函数错误