qt的信号槽原理:moc元对象编译器翻译头文件成moc文件,实现头文件中的信号的函数体和声明信号、槽的索引,加上一个qt_static_metacall的函数等等,然后在connect中的QObjectConnectionListVector的容器中添加这样的一个结构体(如下),通过信号索引从容器中找到这个结构体,然后从结构体中拿到回调函数,就能找到槽函数。
结构体:
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
c->sender = s;
c->signal_index = signal_index;
c->receiver = r;
c->method_relative = method_index;
c->method_offset = method_offset;
c->connectionType = type;
c->isSlotObject = false;
c->argumentTypes.store(types);
c->nextConnectionList = 0;
c->callFunction = callFunction;
从这个原理可以看出实际上是找函数指针的一个过程。
示例模拟:
调用对象:
#include "widget.h"
#include <QApplication>
#include "test.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Test *tmptest = new Test;
return a.exec();
}
#ifndef TEST_H
#define TEST_H
#include <QtWidgets>
class Test
{
public:
Test();
static void testA(void *val);
};
#endif // TEST_H
#include "test.h"
#include "widget.h"
void Test::testA(void* val)
{
qDebug()<<"funcA test:"<<QString::fromUtf8((char*)val);
}
void testB(void)
{
qDebug()<<"funcB test";
}
Test::Test()
{
Widget* tmpw = new Widget;
//注册回调函数,类似connect的连接
tmpw->register_Func(A,testA); //testA:调用类成员函数,注:必须为静态函数。
tmpw->register_Func(B,testB); //testB:调用普通函数
tmpw->show();
}
创建回调函数的头文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtWidgets>
#include <QDebug>
enum FunType
{
A,
B
};
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//----------------声明位置---------------------begin
typedef void(*FuncA)(void*);//该指针*FuncA指向一个返回值为void,参数为void*的函数,FuncA保存这个函数的地址。
FuncA Func_actionA; //类似槽函数
typedef void(*FuncB)(void);
FuncB Func_actionB; //类似槽函数
template <typename T>
void register_Func(FunType type,T fobj) //类似connect的连接源码
{
switch (type) {
case A:
Func_actionA = (FuncA)fobj;
break;
case B:
Func_actionB = (FuncB)fobj;
default:
break;
}
}
//---------------------------------------------end
private slots:
void slottestA();
void slottestB();
private:
Ui::Widget *ui;
QPushButton* m_btn1;
QPushButton* m_btn2;
};
#endif // WIDGET_H
创建回调函数的cpp:
#include "widget.h"
#include "ui_widget.h"
#include "test.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
m_btn1 = new QPushButton("FuncAtest",this);
m_btn2 = new QPushButton("FuncBtest",this);
QVBoxLayout* lay = new QVBoxLayout(this);
lay->addWidget(m_btn1);
lay->addWidget(m_btn2);
this->setLayout(lay);
connect(m_btn1,SIGNAL(clicked()),this,SLOT(slottestA()));
connect(m_btn2,SIGNAL(clicked()),this,SLOT(slottestB()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::slottestA()
{
QString val = "FuncAtest";
Func_actionA(val.toUtf8().data()); //调用位置,类似发信号
}
void Widget::slottestB()
{
Func_actionB(); //调用位置,类似发信号
}