QT 一次触发执行两次槽函数的问题
一、QT 信号槽第五个参数的一些基本概念:
1、Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。
2、Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。
3、Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
4、Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
5、Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。
在Qt开发中,有两种情况能够触发槽函数被触发两次,第一种情况是必现的,属于错误的写法,是指信号和槽关联两次;第二种情况是偶然出现的,是指对信号没有正确理解导致的。
1.信号与槽关联两次
通常这种情况下发生在混合编程的情况下,即既使用了UI来进行布局,又使用来代码来关联信号,使得信号和槽关联两次。不妨以QPushButton中的button为例,通常在使用ui文件布局中自动生成的文件中会调用这样一句话:
QMetaObject::connectSlotsByName();
这样则代表隐式调用connect(button, &QPushButton::clicked, this, &myWidget::on_button_clicked);此时开发者只需要实现on_button_clicked即可,如果再在代码中显示添加信号和槽连接,则会触发槽函数两次
2.QPushButton中的pressed,released, clicked信号
通常这种情况发生在对信号的关联上,以QPushbutton为例,其他的如果有类似情况可以延伸,首先复现这种场景需要正确理解QPushButton中的三种信号:pressed指的是鼠标左键按下的动作,released指的是鼠标左键抬起的动作,clicked指的是鼠标左键按下并抬起的动作,因此触发优先级为pressed>released>clicked.
考虑场景,关联pressed信号,测试鼠标快速点击button,点击button关闭对话框并打印进入对话框的次数,测试发现:在多次尝试后,会出现概率性的一次点击,进入两次对话框的情况,但是关联clicked信号却不会出现这种情况。
避免情况:因此,如果不需要区分三种信号触发的优先级,建议在开发过程中尽量使用clicked信号。