在上周老师说了项目需要学习qt后,就去找了个qt的教程,看了看,教程一上来就开始介绍qt的信号与槽,说这是qt中一个很重要的东西,然后就下一步了……,后面的代码中也没有特别感受到这个的强大与独特(应该是对编程的理解还不够深的原因),就上网找了找技术博客看,发现大部分文章都对菜鸟不太友好,不过最终还是让我找到了一篇让新手也能透彻明白的文章 ,这里记录一下自己的收获。
信号与槽
先让我们看看它的定义:
听着很强,很高级。
简单的用途就是
当一个特定的事件发生时,一个或几个被指定的信号就被发射,槽就是一个返回值为void的函数,如果存在一个或几个槽和该信号相连接,那在该信号被发射后,这个(些)槽(函数)就会立刻被执行
理解倒是不难,不就是触发了一个函数吗?完全感受不到作为一个框架的核心特性的强大。
信号与槽的作用
要感受它的强大还是得从它的作用中体会(也许教程中的老师也是这么想的,只是我没体会到……)。
在图形界面编程中,很多时候我们希望一个可视对象发生某种变化时通知另一个或几个对象,再一个地说,我们希望任 何一类的对象能和其他对象进行通讯。例如,某个数值显示窗口负责显示某个滚动条对象的当前数值,当滚动条对象的值发生变化时,我们希望数值显示窗口能收到 来自滚动条对象发送的“数值改变”的信号,从而改变自己的显示数值。
这些在其他图形框架中可以用回调实现,不过,相比于回调函数,信号和槽机制是类型安全的(没搞太懂为什么安全),一个信号的签名必须与它的接收槽的签名相匹配,这样编译器就可以帮助我们检查类型是否匹配。信号和槽是很宽松的联系在一 起的,一个发射信号的对象不用考虑哪个槽会接收这个信号,接收信号的槽的所在对象也不知道要连接的信号是哪个对象发射的。QT的信号和槽机制可以保证如果 你把一个信号和一个槽连接起来后,槽会在正确的时间使用信号的参数而被调用,信号和槽可以使用任何数量、类型的参数。
换一种说法,在使用信号与槽时你得先连接一下他们。下面是信号与槽的代码实现
使用信号和槽的QT对象:
class UseSignalClass {
Q_OBJECT
public:
UseSignalClass (void) {}
int value (void) const {return _value;}
public slots:
int setValue (int value) {_value = value;} // 定义槽
signals:
void valueChanged (int);
private:
int _value;
}
void UseSignalClass::setValue( int value )
{
if ( value != _value ) {
_val = value;
emit valueChanged(value);
}
}
emit valueChanged(value);这行代码是发射一个信号valueChanged。
要想使一个槽在一个信号被发射后被执行,要显示地进行连接:
UseSignalClass a,b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
然后当a改变时,b也会跟着变,而b的改变不会影响到a,因为b不会给a发信号。
注意
下面是信号与槽的使用中的一些注意事项:
1、信号和槽的机制是非常有效的,但是它不像“真正的”回调那样快。信号和槽稍微有些慢,这是因为它们所提供的灵活性。但这种损失相对来说是比较小的。但要追求高效率的话,比如在实时系统中就要尽量少用这种机制。
2、信号和槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时有可能形成死循环,所以,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样的信号。
3、如果一个信号和多个槽相关联的话,那当这个信号被发射时,与之相关联的槽的执行顺序将是髓机的,且顺序不能指定。
4、宏定义不能用在signal和slot的参数中。
5、构造函数不能用在signals和slots声明区域内。
6、函数指针不能作为信号或槽的参数。
7、信号和槽不能有缺省参数值。
8、信号和槽不能携带模板类参数。
9、嵌套的类不能位于信号和槽区域内,也不能有信号或者槽。
10、友元声明不能位于信号和槽的声明区域内。
总结
学习是一个一步一步的过程,学的时候千万不要太着急,应该克制自己总想直接搞最后一步的想法,毕竟那样学习曲线会太过陡峭,容易让人失去信心,就像这次要不是知道回调,在看相关博客时,肯定也是看的云里雾里的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。