一.定义
-
信号与槽是对象之间的通信机制,是QT专有的机制
-
声明了信号的对象,当其状态改变时,信号就由该对象发射出去,而且该对象只负责发送信号,它不知道另一端是谁在接收这个信号。
-
槽用于接收和处理信号,一个槽并不知道是否有任何信号与自己相连接
信号
信号的声明
- 信号声明是在一个类的头文件中
- signals关键字指出进入了信号声明区,随后即可声明自己的信号。
- 例如,下面语句定义了一个信号:
signals:
void stateChanged(int nNewVal);
信号函数满足以下约束
- 函数返回值是void类型
- 开发人员只能声明、不能实现信号函数
- 只有包含一个信号函数那个类及其派生类才能使用该信号函数
- 信号函数的参数个数、类型由开发人员设定,这些参数的职责是封装类的状态信息,并将这些信息传递给槽函数
- 只有QObject及其派生类才可声明信号函数
槽
- 槽函数和普通的C++成员函数一样,可以被正常调用
- 唯一的特殊性就是很多信号可以与其相关联
- 与其关联的信号被发射时,这个槽就会被调用
- 槽函数可以是 public、protected、private
public slots:
void Function(int nNewVal)
{
//显示变量
qDebug() << "new Values = " << nNewVal;
}
关联信号与槽
-
通过调用QObject::connect()函数可以绑定一个信号函数和一个槽函数,函数常用格式:
connect( sender, SIGNAL ( signal_func() ), receiver, SLOT( slot_func()) )
- 其中sender及receiver 是指向对象的指针,前者指向发射对象,后者指向处理对象
-
signal_func以及slot_func分别是这两个对象中定义的信号函数和槽函数。
-
connect函数另一种形式:(霍亚飞 7.1.1信号和槽 P136)
注意事项
- 信号与槽机制如果使用不当的话,有可能产生死循环
- 如果一个信号与多个槽相联系,当这个信号被发射时,相关的槽被激活的顺序将是随机的
- 信号和槽的参数个数与类型必须一致。信息就是通过这些参数传递的
二.举例
例一.无图形用户界面的简单信号/槽(从空项目开始)
1.exampleA.h
#include <QCoreApplication>
class CExampleA : public Qobject
{
Q_OBJECT
public:
CExampleA()
{ m_Value = 0; }
void SetValue(int nNewVal)
{
if(m_Value == nNewVal)
return;
m_Value = nNewVal;
emit stateChanged(m_Value);
}
signals:
void stateChanged(int nNewVal);
private:
int m_Value;
};
2.exampleB.h
#include <QDebug>
#include <QCoreApplication>
class CExampleB : public QObject
{
Q_OBJECT
public:
CExampleB() {}
public slots:
void Function(int nNewVal)
{
qDebug() << "new Values = " << nNewVal;
}
};
3.main.cpp
#include "exampleA.h"
#include "exampleB.h"
int main(){
CExampleA a;
CExampleB b;
Object::connect(&a, SIGNAL(stateChanged(int)),
&b, SLOT(Function(int)));
a.SetValue(100);
return 0;
}
结果:
例二.使用控件内部定义好的信号/槽 (无UI的QDialog工程文件)
GUI窗口控件(例如按钮、标签、列表、编辑框等等)都预先定义好了若干信号,比如单击按钮就会发出clicked信号,还有诸如双击(doubleClicked)、进入(entered)、按下(pressed)等等信号都是预先在控件内部定义好的。
同时控件中也有一些预先定义好的槽,比如close()、clear()等。
1.dialog.h
//在dialog.h文件头部添加:
#include <QLabel>
#include <QPushButton>
//在dialog.h文件尾部添加声明:
private:
QLabel *label;
QPushButton *btn;
2.dialog.cpp
//在dialog.cpp文件的构造函数添加代码,生成控件:
resize(300,300);
label = new QLabel("label",this);
btn = new QPushButton("Click Me",this);
label->move(150,150);
btn->move(125,110);
//在dialog.cpp文件的构造函数添加代码如下:
connect(btn,SIGNAL(clicked()),label,SLOT(close()));