信号和槽用于对象间的通讯。信号/槽机制是Qt的一个中心特征并且也许是Qt与其它工具包的最不相同的部分。
在图形用户界面编程中,我们经常希望一个窗口部件的一个变化被通知给另一个窗口部件。更一般地,我们希望任何一类的对象可以和其它对象进行通讯。例如,如果我们正在解析一个XML文件,当我们遇到一个新的标签时,我们也许希望通知列表视图我们正在用来表达XML文件的结构。
较老的工具包使用一种被称作回调的通讯方式来实现同一目的。回调是指一个函数的指针,所以如果你希望一个处理函数通知你一些事件,你可以把另一个函数(回调)的指针传递给处理函数。处理函数在适当的时候调用回调。回调有两个主要缺点。首先他们不是类型安全的。我们从来都不能确定处理函数使用了正确的参数来调用回调。其次回调和处理函数是非常强有力地联系在一起的,因为处理函数必须知道要调用哪个回调。
 
在Qt中我们有一种可以替代回调的技术。我们使用信号和槽。当一个特定事件发生的时候,一个信号被发射。Qt的窗口部件有很多预定义的信号,但是我们总是可以通过继承来加入我们自己的信号。槽就是一个可以被调用处理特定信号的函数。Qt的窗口部件又很多预定义的槽,但是通常的习惯是你可以加入自己的槽,这样你就可以处理你所感兴趣的信号。
信号和槽的机制是类型安全的:一个信号的签名必须与它的接收槽的签名相匹配。(实际上一个槽的签名可以比它接收的信号的签名少,因为它可以忽略额外的签名。)因为签名是一致的,编译器就可以帮助我们检测类型不匹配。信号和槽是宽松地联系在一起的:一个发射信号的类不用知道也不用注意哪个槽要接收这个信号。Qt的信号和槽的机制可以保证如果你把一个信号和一个槽连接起来,槽会在正确的时间使用信号的参数而被调用。信号和槽可以使用任何数量、任何类型的参数。它们是完全类型安全的:不会再有回调核心转储(core dump)。
从QObject类或者它的一个子类(比如QWidget类)继承的所有类可以包含信号和槽。当对象改变它们的状态的时候,信号被发送,从某种意义上讲,它们也许对外面的世界感兴趣。这就是所有的对象通讯时所做的一切。它不知道也不注意无论有没有东西接收它所发射的信号。这就是真正的信息封装,并且确保对象可以用作一个软件组件。

槽可以用来接收信号,但它们是正常的成员函数。一个槽不知道它是否被任意信号连接。此外,对象不知道关于这种通讯机制和能够被用作一个真正的软件组件。
你可以把许多信号和你所希望的单一槽相连,并且一个信号也可以和你所期望的许多槽相连。把一个信号和另一个信号直接相连也是可以的。(这时,只要第一个信号被发射时,第二个信号立刻就被发射。)
总体来看,信号和槽构成了一个强有力的组件编程机制。 
 
一个最小的C++类声明:

    class Foo
{
public:
Foo();
int value() const { return val; }
void setValue( int );
private:
int val;
};

一个小的Qt类如下:

    class Foo : public QObject
{
Q_OBJECT
public:
Foo();
int value() const { return val; }
public slots:
void setValue( int );
signals:
void valueChanged( int );
private:
int val;
};

这个类有同样的内部状态,和公有方法来访问状态,但是另外它也支持使用信号和槽的组件编程:这个类可以通过发射一个信号,valueChanged(),来告诉外面的世界它的状态发生了变化,并且它有一个槽,其它对象可以发送信号给这个槽。
所有包含信号和/或者槽的类必须在它们的声明中提到Q_OBJECT。
槽可以由应用程序的编写者来实现。这里是Foo::setValue()的一个可能的实现:

    void Foo::setValue( int v )
{
if ( v != val ) {
val = v;
emit valueChanged(v);
}
}

这个类有同样的内部状态,和公有方法来访问状态,但是另外它也支持使用信号和槽的组件编程:这个类可以通过发射一个信号,valueChanged(),来告诉外面的世界它的状态发生了变化,并且它有一个槽,其它对象可以发送信号给这个槽。
    所有包含信号和/或者槽的类必须在它们的声明中提到Q_OBJECT。
槽可以由应用程序的编写者来实现。这里是Foo::setValue()的一个可能的实现:

    void Foo::setValue( int v )
{
if ( v != val ) {
val = v;
emit valueChanged(v);
}
}

emit valueChanged(v)这一行从对象中发射valueChanged信号。正如你所能看到的,你通过使用emit signal(arguments)来发射信号。
下面是把两个对象连接在一起的一种方法:

    Foo a, b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
b.setValue( 11 ); // a == undefined b == 11
a.setValue( 79 ); // a == 79 b == 79
b.value();

调用a.setValue(79)会使a发射一个valueChanged() 信号,b将会在它的setValue()槽中接收这个信号,也就是b.setValue(79) 被调用。接下来b会发射同样的valueChanged()信号,但是因为没有槽被连接到b的valueChanged()信号,所以没有发生任何事(信号消失了)。
注意只有当v != val的时候setValue()函数才会设置这个值并且发射信号。这样就避免了在循环连接的情况下(比如b.valueChanged() 和a.setValue()连接在一起)出现无休止的循环的情况。
这个例子说明了对象之间可以在互相不知道的情况下一起工作,只要在最初的时在它们中间建立连接。
预处理程序改变或者移除了signals、slots和emit 这些关键字,这样就可以使用标准的C++编译器。
在一个定义有信号和槽的类上运行moc。这样就会生成一个可以和其它对象文件编译和连接成引用程序的C++源文件。

Qt入门(3)——信号和槽的更多相关文章

  1. Qt入门之信号与槽机制

    一. 简介 就我个人来理解,信号槽机制与Windows下消息机制类似,消息机制是基于回调函数,Qt中用信号与槽来代替函数指针,使程序更安全简洁. 信号和槽机制是 Qt 的核心机制,可以让编程人员将互不 ...

  2. Qt学习之信号与槽(一)

    Qt学习之信号与槽(一) 目录 QT的信号与槽机制 在窗口的UI设计中操作添加信号和槽     QT的信号与槽机制   QT的两种机制 在Qt和PyQt中有两种通信机制: 低级事件处理机制(low-l ...

  3. Qt Quick快速入门之信号、槽

    信号和槽主要用于组件之间的通信,类似于.net和java中的委托. 使用QObject::connect方法将信号与槽关联起来,然后信号的发起者发出信号,接受者中的槽函数就会执行. 比如connect ...

  4. Qt中使用信号和槽的一点心得

    信号(Signal)与槽(Slot)-Qt中的典型机制 这一篇文章中都说得很详细了,这里不再重复,只说一点在实际使用中可能会遇到的问题. 1.一个信号不要同时连接几个槽函数,不然执行的顺序是随机的,最 ...

  5. Qt编程之信号与槽-------unresolved external symbol "public: virtual struct QMetaObject const * __thiscall XX::metaObject(void)const

    原因是加入Q_OBJECT这个macro的类,被编译的时候就要用到moc这个命令,所以在VS2010中,没有加入此命令的应用,当然会出错了.所以解决办法是加,或者如果你不使用信号槽可以直接删除. 当要 ...

  6. qt学习:信号,槽

    [C.GUI.Qt.4编程(第二版)](加)布兰切特,(英)萨默菲尔德.扫描版[学习库www.xuexi111.com].pdf 信号和槽是Qt编程的基础,它可以让各种对象联系在一起. 1. 使用co ...

  7. Qt 5中信号和槽的新语法

    QT 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT ...

  8. 【QT学习】信号和槽机制

    QT中发射信号使用 emit 来完成. 类要使用信号和槽机制,必须从QObject或者QObject子类继承.必须在类的定义中加上 Q_OBJECT 宏. 信号和槽连接时,参数类型必须相同. 关键字大 ...

  9. Qt学习笔记----信号与槽实现的四种方式

    1.以按钮为例,首先添加一个按钮,对象名为pushButton,在按钮是右键单击选择“转到槽”即可,在转到槽选择面板(右图)里面选择需要进行的操作,比如单击clicked() 2.选择菜单“编辑”,找 ...

  10. Qt之自定义信号和槽函数

    自定义信号和槽函数: 1.类的声明和实现分别放在.h和.cpp文件中: 2.类声明包含Q_OBJECT宏: 3.信号只要声明不要设计其的实现函数 4.发射信号用emit关键字 5.自定义槽的实现与普通 ...

随机推荐

  1. [LeetCode]Container With Most Water, 解题报告

    前言 难怪LeetCode OJ在找工作时被很多人推荐,发现了这道最大蓄水题目就是美团的笔试最后一道题,当时我霸笔只有着一道题目没有答出来,因此也就没有获得面试机会,可惜了 题目 Given n no ...

  2. Android ViewFlow的一个例子

    完成这个例子的步骤: 1.下载ViewFlow的源码,然后将类ViewFlow放在自己的工程的src的某个包下. 2.下载的源码里有2个工程view flow,viewflow-example.将vi ...

  3. .NET注册页面代码

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI ...

  4. C#链接远程SQL 服务器方法

     C#链接远程SQL 服务器方法第一步:申请花生壳内网版,要求交1块钱给花生壳服务器做验证.第二步:把你自己主机本地连接那里的内网地址不要自动获取,写成192.168.0.105,子网掩码255.25 ...

  5. java执行命令行

    List<String> command = new ArrayList<String>(); command.add("ping"); ProcessBu ...

  6. JAVA彩色图片变灰处理

    File file = new File("F:/firefox.png"); File destFile = new File("F:/pic/" + Sys ...

  7. activiti总结

    1.activiti如何修改登录用户名?在哪个数据库里面添加. 2.activiti的启动和部署在http://activiti.org/userguide/index.html#demo.setup ...

  8. sql 判断表、列、视图等是否存在

    1 判断数据库是否存在 if exists (select * from sys.databases where name = '数据库名')     drop database [数据库名] 2 判 ...

  9. gitHub项目框架使用排名

    项目名称 项目简介                                  使用心得                1. react-native 这 个是 Facebook 在 React ...

  10. starting Intent from ProcessRecord with revoked permission android.permission.CALL_PHONE 的错误

    昨天写个电话拨号器,很简单就一个Edittext和一个button,用来输入号码并且点击按钮拨打电话,但是写好以后报的是安全错误,我上网查了下,原来是缺少授权,于是我在AndroidManifest. ...