信号槽
信号槽示例:connect(QObject* pSender,SIGNAL(sigGetQString(QString)),QObject* pReceiver,SLOT(sltGetQString(QString)));
1、通过MOC(meta object compiler)进行预处理
struct MetaObject
{
const char* pSigNames;
const chra* pSltNames;
};
通过预处理器,将信息提取出来,放置到一个单独的文件中(比如test_object.cpp):
规则很简单,将信号和槽的名字提取出来,放到字符串中。可以有多个信号或槽,按顺序"sig1/nsig2/n"
static const char sig_names[] = “sig1/n”;
static const char slts_names[] = “slot1/n”;
SIGNAL关键字和SLOT关键字包含的内容变成char*
connect(Object *, const char *, Object *, const char *);
2、信号和槽关联
信号和槽之间的关联关系存入到Object中(通过char *字符串关联)
struct Connection
{
Object* pReceiver;
int iMethod;
}
class Object
{
public:
static MetaObject stMeta;
static connnect(Object *, const char *, Object *, const char *);
private:
std::multimap<int,Connection> mapConnections;
};
//通过connect函数将信号和槽的对应关系存入mapConnections
void Object::connect(Object * pSender, const char * pSigName, Object * pReceiver, const char *)
{
//在pSender的pSigNames中查找pSigName所在索引iSigIndex
//在pReceiver的pSltNames中查找pSigName所在索引iSltIndex
Connection c = {pReceiver, iSltIndex};
pSender->mapConnections.insert(std::pair<int, Connection>(iSigIndex, c));
}
3、信号激活
信号通过Object成员函数调用转换最后调用MetaObject中的active函数
class Object
{
public:
void sigGetQString(QString)
...
};
void Object::sigGetQString(QString)
{
emit sig1();
}
void Object::sig1()
{
MetaObject::active(this, iIndex);
}
struct MetaObject
{
const char * sig_names;
const char * slts_names;
static void active(Object * pSender, int idx);
};
void MetaObject::active(Object* pSender, int idx)
{
//通过pSender中的mapConnections,找到对应的pReceiver和pReceiver中的槽函数索引iSltIndex
//找到iSltIndex,然后调用pReceiver中的槽函数
rpReceiver->metacall(iSltIndex);
}
4、槽函数的调用
Object成员函数调用
class Object
{
void metacall(int idx);
...
};
void Object::metacall(int idx)
{
switch (idx) {
case 0:
slot1();
break;
default:
break;
};
}
5、DirectConnection和QueuedConnection情况下的处理
首先看Assistant上的说明
Qt::DirectConnection:
The slot is invoked immediately, when the signal is emitted.
Qt::QueuedConnection:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
可以看到DirectConnection时是在信号发射线程里面调用的slot,而QueuedConnection时,是通过事件相应的,在接收信号的线程里面执行的slot。
实现流程可以参考下图:
在我们使用active()激活信号时,会判断我们的连接方式,当我们使用Qt::QueuedConnection作为连接类型时,槽函数的执行是通过抛出QMetaCallEvent事件,经过Qt的事件循环在接收线程里面调用步骤4中的metacall(),达到异步的效果。