Qt 신호 슬롯 실현 원리

1. 소개

QT 신호 슬롯 실현의 본질은 무엇입니까?
"콜백"

신호 및 슬롯의 기본 원칙에 대해 간략하게 설명합니다.
신호와 슬롯의 실현은 Qt의 Meta Object 시스템을 기반으로합니다. Meta Object 시스템에는 Meta Object 컴파일러가 있습니다. 프로그램이 컴파일되기 전에 전처리 프로세스가 있습니다. 전처리는 클래스의 신호가됩니다. 객체 및 슬롯의 문자열 값. 문자열 또는 기타 순서가 지정된 컨테이너 일 수있는 컨테이너에 저장됩니다.

두 가지 예

간단한 구현

#include <map>
# define slot
# define siginal protected
# define emit

class Object;

struct MetaObject//元对象 每个Object有一个,保存自己拥有的信号和槽函数
{
    
    
	const char* sig_names;
	const char* slts_names;
	static void active(Object* sender, int idx);
};

struct Connection//保存接收方及其序号
{
    
    
	Object* receiver;
	int method;
};

typedef std::multimap<int, Connection> ConnectionMap;
//<信号,接收方>每个Object有一个,保存自己的信号发出时需要通知的接收方。每个信号的接收方可能不止一个,用multimap
typedef std::multimap<int, Connection>::iterator ConnectionMapIt;

static int find_string(const char* str, const char* substr)
{
    
    
	if (strlen(str) < strlen(substr))
		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;
}

class Object
{
    
    
	friend class MetaObject;
public:
	Object() {
    
    };
	virtual ~Object() {
    
    };
	static void connect(Object*sender, const char*sig, Object*receiver, const char*slt);
	void testSignal() {
    
     emit sig1(); }//测试函数

siginal:
	void sig1() //信号
	{
    
     
		cout << "信号发出" << endl;
		MetaObject::active(this, 0);
	}

public slot:
	void slot1() {
    
     cout << "槽函数执行" << endl; }//槽函数

private:
	static MetaObject meta;//保存自己拥有的信号和槽函数
	ConnectionMap connections;//multimap<int, Connection>,
	void metacall(int idx);//根据key去查询对应的槽函数
};

static const char sig_names[] = "sig1\n";//保存对象中所有信号的字符串的容器
static const char slts_names[] = "slot1\n";//保存对象中所有槽函数字符串的容器
MetaObject Object::meta = {
    
     sig_names, slts_names };//初始化元对象

void Object::metacall(int idx)//根据key去查询对应的槽函数
{
    
    
	switch (idx) 
	{
    
    
	case 0:
		slot1();
		break;
	default:
		break;
	};
}

void Object::connect(Object*sender, const char*sig, Object*receiver, const char*slt)//静态成员函数  connect建立信号与槽的连接
{
    
    
	int sig_idx = find_string(sender->meta.sig_names, sig);//查询有没有这个信号和槽函数
	int slt_idx = find_string(receiver->meta.slts_names, slt);
	if (sig_idx == -1 || slt_idx == -1) 
	{
    
    
		perror("signal or slot not found!");
	}
	else //添加
	{
    
    
		Connection c = {
    
     receiver, slt_idx };//保存接收方及其槽函数id
		sender->connections.insert(std::pair<int, Connection>(sig_idx, c));//发送方保存接收方信息
	}
}

void MetaObject::active(Object* sender, int idx)//信号发出,根据发出者找出它的接收方
{
    
    
	ConnectionMapIt it;
	std::pair<ConnectionMapIt, ConnectionMapIt> ret;
	ret = sender->connections.equal_range(idx);//equal_range主要是找在multimap中的key相等的value,也是一个迭代器
	for (it = ret.first; it != ret.second; ++it) 
	{
    
    
		Connection c = (*it).second;//获取之前保存的接受方消息
		c.receiver->metacall(c.method);//接收方执行之前绑定的槽函数
	}
}

int main()
{
    
    
	Object obj1, obj2;
	Object::connect(&obj1, "sig1", &obj2, "slot1");//连接信号
	obj1.testSignal();

	system("pause");
	return 0;
}

결과
여기에 사진 설명 삽입

참조 기사

QT 신호 슬롯

추천

출처blog.csdn.net/GreedySnaker/article/details/114367911