Qt Creator快速入门 第2版 第三章
Qt5.9 c++开发指南 第二章
QT 学习之路 2(4):信号槽
Qt 帮助文档 Signals & Slots
技术点:connect函数的几种写法及连接方式
qt connect函数_Qt signal函数使用类内部类型作为参数导致connect不成功问题分析
信号与槽机制有 Qt 的元对象系统提供,因此使用时需要在类的声明的私有区域添加 Q_OBJECT 宏。
Qt5.9 c++开发指南 第二章
connect 是 QQbject 类的静态函数,而 QObject 是所有 Qt 类的基类,实际调用时可忽略前面的限定符
技术点:connect函数的几种写法及连接方式
[static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the receiver object.
Returns a handle to the connection that can be used to disconnect it later.
You must use the SIGNAL() and SLOT() macros when specifying the signal and the method, for example:
Note that the signal and slots parameters must not contain any variable names, only the type.
示例:
//信号参数多于槽函数的参数,多余的参数被忽略,可以正常连接
connect1 = connect(ui->pushButton_1, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
//第二个和第一个效果相同
connect1 = connect(ui->pushButton_1, SIGNAL(clicked()), this, SLOT(btnClicked()));
注意:槽函数不能是普通的成员函数,必须在槽函数中声明。
QLabel *label = new QLabel;
QLineEdit *lineEdit = new QLineEdit;
QObject::connect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText);
注意:
如果要加参数写法:
class Tst : public QWidget
{
Q_OBJECT
public:
explicit Tst(QWidget *parent = 0);
void fun(void);
signals:
void sig3(const QString &str);
};
// Widget 中槽函数声明,可以为普通成员函数
void slot3(const QString &str);
QMetaObject::Connection connectTst;
connectTst = connect(m_tst, static_cast<void (Tst::*)(const QString&)>(&Tst::sig3),
this, &Widget::slot3);
注意:
QString
则会提示错误。[static] QMetaObject::Connection QObject::connect(const QObject *sender,
PointerToMemberFunction signal, Functor functor)
Lambda 表达式写法:
connect(noteItem, static_cast<void (MyItem::*)(const int, const QString &)>
(&MyNoteItem::sigUpdateItemName),[&](const int index,const QString &str){
//函数实现
});
connect(width_spinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
[=](int v){
this->show();
});
信号与槽的参数个数和类型必须匹配,槽函数的参数个数可以少于信号中的参数,多余的参数会被忽略。
//信号参数多于槽函数的参数,多余的参数被忽略,可以正常连接
connect1 = connect(ui->pushButton_1, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
//第二个和第一个效果相同
connect1 = connect(ui->pushButton_1, SIGNAL(clicked()), this, SLOT(btnClicked()));
连接多个相同的信号与槽,不同的连接各自独立。
示例:对一个按钮建立三个相同的信号与槽的连接,并获取返回值,来判断连接是否成功。
void Widget::connectSigSlot()
{
QMetaObject::Connection connect1, connect2, connect3;
connect1 = connect(ui->pushButton_1, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
connect2 = connect(ui->pushButton_1, SIGNAL(clicked()), this, SLOT(btnClicked()));
connect3 = connect(ui->pushButton_1, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
if (connect1)
{
qDebug() << "connect connect1 successully";
}
if (connect2)
{
qDebug() << "connect connect2 successully";
}
if (connect3)
{
qDebug() << "connect connect3 successully";
}
if (disconnect(connect1))
{
qDebug() << "disconnect connect1 successully";
}
if (connect1)
{
qDebug() << "connect1 is valid";
}
if (connect3)
{
qDebug() << "connect3 is valid";
}
}
void Widget::btnClicked()
{
qDebug() << "button clicked";
}
运行后点击一次按钮 pushButton_1
后输出的结果如下:
connect1
切断连接后,第三个相同的连接仍有效,只有第一个连接无效,三个连接独立。如果希望不重复连接相同的信号和槽,则用连接类型为 Qt::UniqueConnection:
QMetaObject::Connection connectTst, connectTst1;
connectTst = connect(m_tst, SIGNAL(sig3(QString)),
this, SLOT(slot1(QString)), Qt::UniqueConnection);
connectTst1 = connect(m_tst, SIGNAL(sig3(QString)),
this, SLOT(slot1(QString)), Qt::UniqueConnection); //连接失败
注意:上面如果只在 connectTst
中设置类型,则 connectTst1
仍会连接成功,只会在 connectTst
连接时检查该连接有没有重复,因此这里第一个连接 connectTst
不用设置连接类型。
connect
函数中槽函数的参数不能包含任何变量名,只有类型。
类型中不用指明 const 和引用,connect 会忽略它们。
如果类型中将 const 和引用写上,要么写全,要么不写,都没问题,如果只写一部分则不能连接成功。
QMetaObject::Connection connectTst, connectTst1, connectTst2;
connectTst = connect(m_tst, SIGNAL(sig1(const QString&)), this, SLOT(slot1(const QString&)));
connectTst1 = connect(m_tst, SIGNAL(sig1(QString&)), this, SLOT(slot1(QString&)));
connectTst2 = connect(m_tst, SIGNAL(sig1(QString)), this, SLOT(slot1(QString)));
if (connectTst)
{
qDebug() << "connect connectTst successully";
}
if (connectTst1)
{
qDebug() << "connect connectTst1 successully";
}
if (connectTst2)
{
qDebug() << "connect connectTst2 successully";
}
第一个连接和第三个连接有效,第二个连接失败,会有如下提示:
QObject::connect: No such signal Tst::sig1(QString&) in ..\QLabel\src\widget.cpp:19
如果 connect
函数中信号或槽函数参数中有变量名会出错。
connect(m_tst, SIGNAL(sig1(const QString&)), this, SLOT(slot1(const QString&)));
m_tst = new Tst;
上面,如果在建立信号与槽连接时, m_tst
为空指针,则连接建立失败,会有如下提示:
QObject::connect: Cannot connect (nullptr)::sig1(const QString&) to
Widget::slot1(const QString&)
如果 Qt::ConnectionType 类型为 Qt::QueuedConnection,信号与槽函数的参数必须是 QVariant,如果是自定义类型,需要注册类型。因为 Qt 需要复制参数存起来,因此要是 Qt 元对象系统能识别的类型。
测试时连接类型选择 Qt::DirectConnection 后用自定义参数不注册也不会出错,但改为 Qt::QueuedConnection 后必须注册才能连接成功。
//头文件中
typedef struct
{
int i;
int j;
}MyStruct;
Q_DECLARE_METATYPE(MyStruct)
//.cpp 文件,在连接前注册
qRegisterMetaType<MyStruct>();
connect(m_tst, SIGNAL(sig2(MyStruct)), this, SLOT(slot2(MyStruct)), Qt::QueuedConnection);
注册自定义类型有两步:
Q_DECLARE_METATYPE(Type)
宏让该类型被元对象系统识别。qRegisterMetaType()
注册类型,能在运行时被解析。Q_DECLARE_METATYPE(Type) 介绍:
注意:如果类型在某个名称空间中,也要带上名称空间。
namespace MyType {
typedef struct
{
int i;
int j;
}MyStruct;
}
Q_DECLARE_METATYPE(MyType::MyStruct)
qRegisterMetaType<MyType::MyStruct>();
connect(m_tst, SIGNAL(sig2(MyType::MyStruct)), this,
SLOT(slot2(MyType::MyStruct)), Qt::QueuedConnection);
//或者写成下面形式,不用写参数
connect(m_tst, &Tst::sig2, this, &Widget::slot2);
槽函数名字最好不要与 qt 界面中自动生成的槽函数名字相同。
如按钮 pushButton_2
的 clicked()
信号,在界面自动的槽函数名字为 on_pushButton_2_clicked
,如果自己建立一个信号 pressed()
对应的槽函数也为 on_pushButton_2_clicked
,则当按钮按下时,会执行一次槽函数,然后释放后再执行一次。
Qt 帮助文档 Signals & Slots
信号无返回值,也无需实现信号定义,但信号需要声明在 signals:
中。
槽函数执行的顺序按照建立连接的顺序执行。
多个信号连可以接到同一个槽。
一个信号发射时,发射另一个信号。
Qt 帮助文档 Signals & Slots
技术点:connect函数的几种写法及连接方式
通常,一个信号被发射后,槽函数立马执行,执行完槽函数后才会继续执行发射信号后面的代码。
但是,如果连接的类型是 Qt::QueuedConnection,则会先执行 emit 发射信号后面的代码,在之后才会执行槽函数。
connect
中槽函数写普通成员函数,构建不会提示错误,但触发信号时,不会进入该函数执行。格式二无该要求,槽函数也可以是普通的成员函数。利用 connect 的返回值
QMetaObject::Connection connectTst3 = connect(m_tst, &Tst::sig2, this, &Widget::slot2);
disconnect(connectTst3);
m_tst->disconnect(m_tst);
//等价于下面的写法,m_tst 对象发送的所有信号,接受者为 m_tst 的所有槽函数屏蔽
disconnect(m_tst, nullptr, m_tst, nullptr);
m_tst->disconnect();
//等价于下面的写法
disconnect(m_tst, 0, 0, 0);
当有多个信号连接到一个槽函数时,可以通过该函数区分信号来源,如一个 buttonGroup 包含多个按钮。
QGroupBox* groupBox = dynamic_cast<QGroupBox*>(sender());
if(groupBox->objectName().compare(ui->groupBox_1->objectName()) == 0)
{
}