信号函数和槽函数是Qt在C++的基础上新增的功能,功能是实现对象之间的通信。
实现信号槽需要有两个先决条件:
通信的对象必须是从QObject派生出来的
QObject是Qt所有类的基类。
类中要有Q_OBJECT宏
最常用且最基础的信号槽连接函数如下所示:
// 参数1:发送者,信号槽触发的来源的对象
// 参数2:信号函数,发送者的触发动作,使用SIGNAL()包裹
// 参数3:接收者,信号槽触发后执行动作的对象
// 参数4:槽函数,接收者执行的动作,使用SLOT()包裹
QObject::connect(const QObject * sender,
const char * signal,
const QObject * receiver,
const char * method) [static]
按照不同的情况,分为三种情况进行学习:
可以使用disconnect函数断开已经连接的信号槽,参数与connect连接时保持一致。返回值为是否断开成功,如果已经不连接了,则会断开失败,此时不会有任何影响。
这种情况下信号函数和槽函数都是Qt内置的,程序员只需要找到对应关系后连接即可。
【例子】点击按钮,关闭窗口。
分析:
发射者:按钮
信号函数:点击
接收者:窗口
槽函数:关闭
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
};
#endif // DIALOG_H
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(300,300);
btn = new QPushButton("关闭",this);
btn->move(100,150);
// 发射者:按钮
// 信号函数:点击
// 接收者:窗口
// 槽函数:关闭
connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}
Dialog::~Dialog()
{
delete btn;
}
【例子】点击按钮,窗口向右侧移动10个像素,向下移动10个像素,同时输出当前的窗口坐标。
分析:
发射者:按钮
信号函数:点击
接收者:窗口
槽函数:自定义
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
#include
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
private slots: // 槽函数
void mySlot(); // 头文件声明
};
#endif // DIALOG_H
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(300,300);
btn = new QPushButton("关闭",this);
btn->move(100,150);
// 发射者:按钮
// 信号函数:点击
// 接收者:窗口
// 槽函数:自定义
connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}
void Dialog::mySlot() // 源文件定义
{
// 先获得当前的窗口坐标
int x = this->x();
int y = this->y();
// 窗口向右侧移动10个像素,向下移动10个像素
move(x+10,y+10);
// 同时输出当前的窗口坐标。
qDebug() << x+10 << y+10;
}
Dialog::~Dialog()
{
delete btn;
}
这种方式主要用于解决复杂问题,所以在本节强行使用。
信号函数具有以下特点:
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
private slots:
void mySlot();
// 声明信号函数
signals:
void mySignal(); // 自定义信号
};
#endif // DIALOG_H
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(400,400);
btn = new QPushButton("关闭",this);
btn->move(100,150);
connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}
void Dialog::mySlot()
{
// 发射自定义信号
emit mySignal();
}
Dialog::~Dialog()
{
delete btn;
}
信号槽支持参数传递,信号函数可携带参数发送给槽函数。
【例子】点击按钮,按钮上显示点击的次数。
正常的做法不使用信号槽传参:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
int count; // 点击的次数
private slots:
void btnClickedSlot(); // 点击按钮的槽函数
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent),count(0) // 构造初始化列表
{
resize(400,400);
btn = new QPushButton("0",this);
btn->move(100,200);
connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}
void Dialog::btnClickedSlot()
{
// 显示点击的次数
count++; // count是成员变量
// int → 字符串
QString text = QString::number(count);
// 给按钮设置显示内容
btn->setText(text);
}
Dialog::~Dialog()
{
delete btn;
}
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
int count; // 点击的次数
private slots:
void btnClickedSlot(); // 点击按钮的槽函数
void countSlot(int); // 自定义槽函数2
signals:
// 能发参数的自定义信号
void countSignal(int);
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent),count(0) // 构造初始化列表
{
resize(400,400);
btn = new QPushButton("0",this);
btn->move(100,200);
connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
connect(this,SIGNAL(countSignal(int)),
this,SLOT(countSlot(int)));
}
void Dialog::btnClickedSlot()
{
count++;
// 发射带参数的自定义信号
emit countSignal(count);
}
/**
* @brief Dialog::countSlot
* @param count此数值并非成员变量,而是信号函数发射来的
*/
void Dialog::countSlot(int count)
{
// int → 字符串
QString text = QString::number(count);
// 设置显示
btn->setText(text);
}
Dialog::~Dialog()
{
delete btn;
}
下面是一个一对多和多对一的例子:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
#include
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton *btn1; // 一对多
QPushButton* btn2;
private slots:
void btnClickedSlot1();
void btnClickedSlot2();
void btnClickedSlot3();
void btnClickedSlot4();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(400,400);
btn1 = new QPushButton("1",this);
btn1->move(100,100);
btn2 = new QPushButton("2",this);
btn2->move(200,200);
// 一对多
connect(btn1,SIGNAL(clicked()),
this,SLOT(btnClickedSlot1()));
connect(btn1,SIGNAL(clicked()),
this,SLOT(btnClickedSlot2()));
// 一对一
connect(btn2,SIGNAL(clicked()),
this,SLOT(btnClickedSlot3()));
// 多对一
connect(btn1,SIGNAL(clicked()),
this,SLOT(btnClickedSlot4()));
connect(btn2,SIGNAL(clicked()),
this,SLOT(btnClickedSlot4()));
}
void Dialog::btnClickedSlot1()
{
qDebug() << "a";
}
void Dialog::btnClickedSlot2()
{
qDebug() << "b";
}
void Dialog::btnClickedSlot3()
{
// 槽函数也是成员函数
this->btnClickedSlot1();
btnClickedSlot2();
}
void Dialog::btnClickedSlot4()
{
qDebug() << "发射者是谁?";
// 多对一的情况下如何区分发射者:
if(btn1 == sender())
{
qDebug() << "发射者是btn1";
}else if(btn2 == sender())
{
qDebug() << "发射者是btn2";
}
}
Dialog::~Dialog()
{
delete btn1;
delete btn2;
}
上面要注意的点使用了sender()函数,该函数用来返回信号发送者对象的首地址,当有多个发送者对应同一个槽函数时,可以用来判断是谁发的消息。