QT5信号槽个人总结

10 篇文章 0 订阅

一、关于qt信号槽的理解

这里沿用豆子大神的话说,所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。
备注:强烈推荐豆子大神的Qt学习之路
提示:以下个人浅见,讲的过于直白,大佬绕道。

二、Qt5信号槽基本使用

在Qt5中,QObject::connect()有五个重载:

QMetaObject::Connection connect(const QObject *, const char *,
                                const QObject *, const char *,
                                Qt::ConnectionType);

QMetaObject::Connection connect(const QObject *, const QMetaMethod &,
                                const QObject *, const QMetaMethod &,
                                Qt::ConnectionType);

QMetaObject::Connection connect(const QObject *, const char *,
                                const char *,
                                Qt::ConnectionType) const;

QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
                                const QObject *, PointerToMemberFunction,
                                Qt::ConnectionType)

QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
                                Functor);

对五个重载进行分析:
1.函数返回值都是QMetaObject::Connection类型,这个返回值一般很少有用到,关于返回值的意义qt官方文档的说明是:
Returns a handle to the connection that can be used to disconnect it later.
返回该连接的句柄,以后可用于断开连接。也就是说我们可以手动断开这个connect,我们绑定widget的Signal_DoSomeThing信号到widget的slot_toDo槽,然后当槽函数执行完成后手动断开连接,伪代码如下:

auto connection = QObject::connect(this, &MyWidget::Signal_DoSomeThing, this, &MyWidget::slot_toDo);//auto:自动类型推断,见c++11特性
emit Signal_DoSomeThing();
disconnect(connection );	//断开连接的时候再发出信号无法再触发槽函数

显然一般情况下我们不会这么做,这种应用场景一般结合c++11的lambda 表达式应用,我们将上句代码进行变形:

void func1()
{
	int para = 1;
	auto connection = QObject::connect(this, &MyWidget::Signal_DoSomeThing, [this, &para](){
		//ToDo
	});
	emit Signal_DoSomeThing();
	disconnect(connection );	//断开连接的时候再发出信号无法再触发槽函数
}

void func2()
{
	QString para = "a";
	auto connection = QObject::connect(this, &MyWidget::Signal_DoSomeThing, [this, &para](){
		//ToDo
	});
	emit Signal_DoSomeThing();
	disconnect(connection );	//断开连接的时候再发出信号无法再触发槽函数
}

这样我们就可以根据需求灵活变更,使用完成后切断当前连接,代码耦合性更好。
似乎我们按照我们的想法实现了它该有的功能,但实际使用这根本不需要信号槽连接,直接调函数不就完了,显然不应该是这种连接完后马上就去发信号执行槽这种做法,而是由外部触发这个信号,那外部怎么触发这个信号呢,必然是函数内执行了某个操作,执行完毕后触发这个信号,然后再执行即时绑定的槽,而这个函数内执行的某个操作,必然是应用于多线程的,如果是单线程的,那也就直接调函数了,还需要信号槽吗。
梳理一下,我们的应用逻辑应该是绑定一个信号槽,然后执行一个线程操作,线程执行完毕后触发信号,执行即时绑定槽,执行完毕后断开信号槽连接。那这里就涉及到一个问题,我们需要等待槽函数执行之后再断开连接,槽函数执行又需要等待线程执行完毕触发信号后再执行,为了不影响主线程刷新,QEventLoop很好的解决了这个问题。
到这里就比较清晰了,举一个典型例子,我们在给服务器发消息的时候,希望即时收到回复并作出相应处理,伪代码如下:

void getMsgFromServerAndToDo(QString msg)
{
	QString para = "a";
	QEventLoop eventLoop;
	auto connection = QObject::connect(this, &MyWidget::Signal_ResieveMsg, [this, &para, &eventLoop](const QString &msgResult){
		//ToDo
		...
		eventLoop.quit();	//退出事件循环
	});
	sendMsg(msg);	//发送消息后进入事件循环,等待接收到消息后触发Signal_ResieveMsg
	eventLoop.exec();
    disconnect(c);
}

结合这个例子来看,是不是这种设计就非常巧妙,那这个para有什么用?当然是为接收到的数据处理用啊,比如你要比对本地与服务器数据,比如你要结合服务器数据存储到数据结构。
2.信号槽的连接参数中,sender 和receiver 类型是const QObject *,只有signal 和slot的类型不一样,
分析第一个,signal和slot的类型的类型都是const char *,Qt4中也包含了同样的重载,因此,这种方式Qt4和Qt5是兼容的:

QObject::connect(button, SIGNAL(clicked()),
                     this,    SLOT(slot_toDo()));

SIGNAL和SLOT这两个宏,将两个函数名转换成了字符串,信号加前缀2,槽加前缀1。它与以下代码是等效的:

connect(button,”2clicked(), this,1slot_toDo());

分析第二种,signal和slot的类型的类型都是const QMetaMethod &,我们可以将每个函数看做是QMetaMethod的子类。因此,这种写法可以使用QMetaMethod进行类型比对。
分析第三种,缺少了 receiver。这个函数其实是将 this 指针作为 receiver。
分析第四种,signal 和 slot 类型则是PointerToMemberFunction。看这个名字就应该知道,这是指向成员函数的指针,而Qt4无此重载,这也解释了为什么Q5可以使用如下形式而Qt4不可以:

QObject::connect(button, &QPushButton::clicked,
                     this,  &Qwidget::slot_toDo);

分析第5种,最后一个参数是Functor类型,Functor类型是什么?也就是C++中的仿函数,至于什么是仿函数这里不作解释,而Functor类型,使得槽函数可以接受任何成员函数、static 函数、全局函数以及 Lambda 表达式。
######先写这么多…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值