Qt 信号与槽机制

下部分代码来自于C++实现自己的信号槽_小青年儿-CSDN博客,我自己添加了传递参数的部分 

#ifndef MY_OBJECT
#define MY_OBJECT

#include <map>

#define my_slots
#define my_signals protected
#define my_emit

class MyObject;

struct MetaObject
{	
	//signal字符串
	const char* sig_names;
	//slot 字符串
	const char* slts_names;
	static void active(MyObject* sender,int idx,void** argv);
};

struct Connection
{
	//接收者
	MyObject* receiver;
	//保存的并不是 槽函数,而是slot在receiver里的序号,到时候根据此序号调用对应槽函数
	int method;
};

//key 代表signal在sender里的序号,value就是 slot所需的信息
typedef std::multimap<int,Connection> ConnectionMap;
typedef std::multimap<int,Connection>::iterator ConnectionMapIt;

class MyObject
{
	//这一部分就是完整的signal和slot信息
	static MetaObject meta;
	void metacall(int idx,void** argv);
public:
	MyObject();
	virtual ~MyObject();
	static void Connect(MyObject* sender,const char* signal,
		MyObject* receiver,const char* slot);
	void testSignal();
my_signals:
	void mysig(int,double);
public my_slots:
	void myslot(int ,double);
	friend struct MetaObject;
private:
	//其实signal,slot链接map在发送object里的,毕竟调用slot
	//是从发送方开始的
	ConnectionMap connections;
};

#endif
#include "StdAfx.h"
#include "MyObject.h"
#include <string.h>
#include <stdio.h>

MyObject::MyObject(void)
{
}

MyObject::~MyObject(void)
{
}

//去signal和slot字符串中查找signal和slot的序号
static int find_string(const char* str,const char* substr)
{
	if (strlen(substr)>strlen(str))
		return -1;
	int idx = 0;
	int len = strlen(substr);
	bool start = true;
	const char* pos = str;
	while(*pos)
	{
		if (start&&!strncmp(pos,substr,len)&&pos[len]=='\n')
			return idx;
		start = false;
		if(*pos=='\n')
		{
			idx++;
			start = true;
		}
		pos++;		
	}
	return -1;
}

//把sender的signal与receiver的slot保存到sender的map里
void MyObject::Connect(MyObject* sender,const char* signal,
	MyObject* receiver,const char* slot)
{
	int sig_idx = find_string(sender->meta.sig_names,signal);
	int slt_idx = find_string(receiver->meta.slts_names,slot);
	if(sig_idx==-1||slt_idx==-1)
		printf("signal or slot not found");
	else
	{
		Connection c = {receiver,slt_idx};
		//保存在 sender的 map里
		sender->connections.insert(std::pair<int,Connection>(sig_idx,c));
	}
}

void MyObject::myslot(int value1,double value2){
	printf("我是槽,不是草 传的参数:int:%d double %lf\n",value1,value2);
};

//这个函数大概就是sender与receiver的中间件,利用保存在MetaObject
//里的signal字符串与slot字符串,去调用那个和signal相应的receiver的slot
void MetaObject::active(MyObject* sender,int idx,void** argv)
{
	ConnectionMapIt it;
	std::pair<ConnectionMapIt,ConnectionMapIt> ret;
	ret = sender->connections.equal_range(idx);
	for (it = ret.first;it!=ret.second;++it)//依次调用某信号对应的N个槽
	{
		Connection c = (*it).second;
		c.receiver->metacall(c.method,argv);
	}
}

void MyObject::testSignal()
{
	my_emit mysig(11,22.2);
}

//每一个\n就分隔出来一个 signal信号 的字符串,这个字符串来自signal信号函数名字,
//在Qt里这一部分功能是由moc实现的
static const char sig_names[] ="mysig\n";
//slot字符串产生原理如上
static const char slt_names[] ="myslot\n";

MetaObject MyObject::meta = {sig_names,slt_names};

//Qt里面定义的signal函数只有定义,然后靠moc生成函数体
void MyObject::mysig(int value1,double value2)
{
	//参数是靠void* 数组传递过去的
	void* argv[] = {nullptr,reinterpret_cast<void*>(&value1),reinterpret_cast<void*>(&value2)};
	//在signal函数里调用active,最终会调用到相应的slot函数
	MetaObject::active(this,0,argv);
}

//按照slot号去调用相应的函数
void MyObject::metacall(int idx,void** argv)
{
	switch(idx)
	{
	case 0:
		//这里把void*参数强转成slot的参数,moc在编译阶段就已经知道slot参数类型了
		myslot(*reinterpret_cast<int*>(argv[1]),*reinterpret_cast<double*>(argv[2]));
		break;
	default:
		break;
	}
}
//main.cpp
#include "stdafx.h"
#include "MyObject.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	MyObject obj1,obj2;
	MyObject::Connect(&obj1,"mysig",&obj2,"myslot");
	obj1.testSignal();
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值