QObject::connect 创建信号和槽的连接
创建信号和槽的连接
方法一:connect 配合宏
connect 方法有多个重载,第一种方法是具体是通过下面这个重载:
static QMetaObject::Connection connect(QObject *sender, char *signal, QObject *receiver, char *member, Qt::ConnectionType = Qt::AutoConnection);
简单来说就是 connect(发送者,信号,接受者,槽)
。假设我们又一个叫做 demo_button 的按钮,每次点击程序都会输出 Hello World,那么就如可以如下实现。
在头文件中通过 private slots
定义槽函数:
class TestFeature : public QMainWindow {
// 其他部分已省略
private slots:
void say_hello();
};
然后在构造函数中去对槽函数进行关联:
TestFeature::TestFeature(QWidget *parent) : QMainWindow(parent), ui(new Ui::TestFeature) {
ui->setupUi(this);
QObject::connect(ui->demoButton, SIGNAL(clicked(bool)), this, SLOT(sayHello()));
}
方法二:利用潜规则自动关联
还有一种不直观的方式是通过把槽函数命名为 <返回值类型> on_控件名称_信号([参数列表])
,这样可以实现控件和槽函数之间的自动关联(也可以在 Qt Design 中右键选择控件,选择 Go to slot... 即自动创建该槽函数的定义和空实现)。
在头文件中声明槽函数:
class TestFeature : public QMainWindow {
// 其他部分已省略
private slots:
void on_demo_button_clicked();
};
此时两者已经进行关联,不需要任何额外的操作。
方法三:不再需要 SIGNAL 和 SLOT
在 Qt5 当中你可以不需要 SIGNAL 和 SLOT 函数就能够进行关联。
这时候在头文件声明的时候只需要使用普通的访问修饰符就可以了:
class TestFeature : public QMainWindow {
// 其他部分已省略
private:
void say_hello();
};
在关联的时候信号函数和槽函数直接传入即可:
connect(ui->demo_button, &QPushButton::clicked, this, &TestFeature::say_hello);
这种方法使用的重载则是:
static inline QMetaObject::Connection
connect(typename QtPrivate::FunctionPointer<Func1>::Object *sender,
Func1 signal,
typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context,
Func2 &&slot,
Qt::ConnectionType type = Qt::AutoConnection)
这种写法虽然简洁,相比于通过 SIGNAL 和 SLOT 宏的方式添加了编译时检查,但是无法处理重载问题——如果上面例子中的 say_hello
函数有重载对象的话, connect
函数处甚至没有办法通过编译。
方法四:Lambda 函数作为槽函数
为了解决上面的问题使用 Lambda 函数作为槽函数是一种办法。
假设 say_hello
函数有一个重载对象:
class TestFeature : public QMainWindow {
// 其他部分已省略
private:
void say_hello();
void say_hello(int);
};
然后在关联的时候通过 Lambda 函数明确具体调用的重载对象:
connect(ui->demo_button, &QPushButton::clicked, this, [=]() { this->say_hello(); });
connect(ui->demo_button, &QPushButton::clicked, this, [=](int n) { this->say_hello(7); });
当然了,如果只是为了解决函数重载问题,使用指针函数也是能够解决问题的,比如这样:
void (TestFeature::*say_hello_fp)() = &TestFeature::say_hello;
void (TestFeature::*say_hello_int_fp)(int) = &TestFeature::say_hello;
connect(ui->demo_button, &QPushButton::clicked, this, say_hello_fp);
connect(ui->demo_button, &QPushButton::clicked, this, say_hello_int_fp);
不过使用 Lambda 表达式也有捕获环境变量的好处。
方法五:通过 QOverload 解决重载问题
其实这个应该算第六种方法,通过函数指针创建槽函数应该也能算一种。
为了解决重载问题,你可以通过 QOverload::of
来解决无法区分重载函数的问题:
connect(ui->demo_button, &QPushButton::clicked, this, QOverload<int>::of(&TestFeature::say_hello));
connect(ui->demo_button, &QPushButton::clicked, this, QOverload<>::of(&TestFeature::say_hello));