信号与槽机制是Qt的核心特征,也是Qt不同于其他开发框架的最突出特征,该机制主要实现Qt中两个对象之间的通信。
信号与槽之间的关联可以实现:
一个信号关联一个槽;
一个信号关联多个槽;
多个信号关联一个槽;
信号关联信号;
1、采用关键字signals声明一个信号,前面不能用public、private、protected等限定符,信号默认是public,表明信号可以在任何地方发射,但建议只在该类和子类中发射该信号;
2、信号只需要声明,不需要定义;
3、信号没有返回值,返回类型只能是void,但信号可以传递参数;
4、只有QObject类及其子类才能采用信号与槽机制,且需要在类声明中添加Q_OBJECT宏;
5、发射信号采用emit 关键字;
信号声明,例:
>signals :
void landownerSignal(int number);
void brownTwoSignal(QString str);
void brownBigSignal();
信号发射,例:
1、带int参数
emit landownerSignal(4);
2、带QString类型参数
QString str = QString::fromLocal8Bit(“我熊二,飞机带翅膀!”);
emit brownTwoSignal(str);
3、不带参数
emit brownBigSignal();
例:
public:
void landowner(int card);
public slots:
void on_pushButton_brownTwo_clicked();
void on_pushButton_brownBig_clicked();
void on_pushButton_landowner_clicked();
//
void brownTwo(QString card);
void brownBig();
在Qt5中信号与槽有三种关联形式。
QObject类中的connect()函数原型如下:
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
sender,发射信号的对象;
signal,要发射的信号,使用SIGNAL()宏;
receiver,接受信号的对象;
method,执行的槽函数;使用SLOT()宏;
Qt::AutoConnection,表示默认关联方式为自动关联
使用这类connect()重载函数时,槽函数必须采用添加关键slots进行声明的槽函数;
例:
> connect(this, SIGNAL(brownTwoSignal(QString)), this, SLOT(brownTwo(QString )));
Qt5中新增的connect重载函数原型如下:
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
由上可知,这种重载方式与第一种的区别在于:signal和method两个参数的类型由原来的const char*类型变为了函数指针;
因此,信号与槽不必再采用SIGNAL()和SOLT()的形式,槽函数也不必采用slots关键字声明,满足参数要求的成员函数即可。
例:
connect(this, &QtSlotLearn::landownerSignal, this, &QtSlotLearn::landowner);
信号与槽的自动关联方式,一般是针对控件的内部信号而言。通过特定格式来命名槽函数,即可实现信号与槽的自动关联;
public slots:
void on_pushButton_brownTwo_clicked();
//控件名为pushButton_brownTwo,信号为clicked();
说明: 当点击名为“”pushButton_brownTwo“”的按钮时,自动发射clicked()信号,且该信号会自动关联到槽函数 on_pushButton_brownTwo_clicked()上;
限制条件
这种自动关联信号与槽的方式非常简洁,小码哥在用QtDesigner写界面的时候喜欢用这种自动关联的形式来进行槽与信号的连接,但这种自动关联的方式也有一些限制;
1、需要调用connectSlotsByName()函数来支持信号与槽的自动关联;
2、需要使用setObjectName()来指定控件名,其控件命名需在connectSlotsByName()函数之前实现;
3、一般在setupUi()函数中已经调用了connectSlotsByName()函数,如果需要对手动代码添加的控件进行信号槽的自动关联,采用setObjectName()指定控件名应该在setupUi()函数之前
这里小码哥建议,如果你是利用代码添加的控件,要实现信号与槽,就直接采用connect,简单明了也省心;
如果是QtDesigner界面上添加的部件,且部件的内置信号满足你都需要,则可以直接使用自动关联方式;
控件的内置信号,QtDesigner上可以很容易找到;
pushButton内置信号如下:
以下小码哥给出一个案例,该案例中包含了三种信号与槽的关联方式;
头文件:QtSlotLearn.h
#pragma once
#include
#include "ui_QtSlotLearn.h"
class QtSlotLearn : public QMainWindow
{
Q_OBJECT
public:
QtSlotLearn(QWidget *parent = Q_NULLPTR);
private:
Ui::QtSlotLearnClass ui;
public:
//一般成员函数
void landowner(int card);
public slots:
//自动关联槽
void on_pushButton_brownTwo_clicked();
void on_pushButton_brownBig_clicked();
void on_pushButton_landowner_clicked();
//槽
void brownTwo(QString card);
void brownBig();
signals :
//各种传参和不传参的信号
void landownerSignal(int number);
void brownTwoSignal(QString str);
void brownBigSignal();
};
QtSlotLearn.cpp 文件;
#include "QtSlotLearn.h"
#include
QtSlotLearn::QtSlotLearn(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.pushButton_brownTwo->setEnabled(true);
ui.pushButton_brownBig->setEnabled(false);
ui.pushButton_landowner->setEnabled(false);
this->setWindowTitle(QString::fromLocal8Bit("熊熊斗地主"));
connect(this, SIGNAL(brownTwoSignal(QString)), this, SLOT(brownTwo(QString )));
connect(this, &QtSlotLearn::landownerSignal, this, &QtSlotLearn::landowner);
connect(this, SIGNAL(brownBigSignal()), this, SLOT(brownBig()));
}
//***********自动连接处理此刻的clicked()信号槽函数:
//该函数自动连接控件pushButton_brownTwo的clicked()信号
void QtSlotLearn::on_pushButton_brownTwo_clicked()
{
QString str = QString::fromLocal8Bit("我熊二,飞机带翅膀!");
emit brownTwoSignal(str);
}
//该函数自动连接控件pushButton_brownBig的clicked()信号
void QtSlotLearn::on_pushButton_brownBig_clicked()
{
emit brownBigSignal();
}
//该函数自动连接控件pushButton_landowner的clicked()信号
void QtSlotLearn::on_pushButton_landowner_clicked()
{
emit landownerSignal(4);
}
//***********利用connect()函数手动链接的槽函数;
void QtSlotLearn::brownTwo(QString card)
{
//添加QLabel显示文字
QLabel* labelTemp = new QLabel(ui.frame);
labelTemp->setText(card);
labelTemp->move(50,50);
labelTemp->show();
//下家出牌,设置按钮是否可用;
ui.pushButton_brownTwo->setEnabled(false);
ui.pushButton_brownBig->setEnabled(false);
ui.pushButton_landowner->setEnabled(true);
}
void QtSlotLearn::brownBig()
{
//设置显示文字
QString str = QString::fromLocal8Bit("光头强敢欺负熊二,看我双王!");
//添加QLabel显示文字
QLabel* labelTemp = new QLabel(ui.frame);
labelTemp->setText(str);
labelTemp->move(200, 100);
labelTemp->show();
//下家出牌,设置按钮是否可用;
ui.pushButton_brownTwo->setEnabled(true);
ui.pushButton_brownBig->setEnabled(false);
ui.pushButton_landowner->setEnabled(false);
}
//***********非槽函数的成员函数:
void QtSlotLearn::landowner(int card)
{
//设置显示文字
QString str = QString::fromLocal8Bit("嘿嘿,小熊熊,看强哥我") + QString::number(card) + QString::fromLocal8Bit("个二,灭了你");
//添加QLabel显示文字
QLabel* labelTemp = new QLabel(ui.frame);
labelTemp->setText(str);
labelTemp->move(100, 300);
labelTemp->show();
//下家出牌,设置按钮是否可用;
ui.pushButton_brownTwo->setEnabled(false);
ui.pushButton_brownBig->setEnabled(true);
ui.pushButton_landowner->setEnabled(false);
}
以上代码实现一段熊出没中斗地主的情景(小码哥深受熊出没的毒害^_^!)。
击当前玩家按钮,发射clicked()信号,调用对应槽函数来实现激活下一个玩家按钮,并打出手中的牌的功能;
打牌的次序:熊二——>光头强——>熊大!
信号与槽的机制非常灵活便捷,但是在使用的时候一定要注意以上提及的一些细节,稍稍错过一些细节,这种机制就很容易失效!
1、《Qt Creator快速入门》