Qt/C++ 临时屏蔽控件信号(signal)的实用方法

您所在的位置:网站首页 qt自定义信号发送 Qt/C++ 临时屏蔽控件信号(signal)的实用方法

Qt/C++ 临时屏蔽控件信号(signal)的实用方法

2023-10-18 22:28| 来源: 网络整理| 查看: 265

1. 背景

在使用Qt的控件时,我们大概率会使用Qt的信号与槽(signal-slot)的机制来实现自己的UI交互逻辑。由于Qt内置控件的信号种类是有限的,我们常常会遇到如下窘境:

以常见的QComboBox控件为例,它提供了一个非常实用的信号void currentIndexChanged(int index),每当该控件中的当前选项通过用户交互或以编程方式更改时,都会发送此信号。注意到,当我们调用void QComboBox::setCurrentIndex(int index)时,也会导致该信号被触发。那么,假设有这么一个场景,我们使用了一个只含有两个选项的QComboBox(0:Item1和1:Item2),每当用户变更这个选项时,我们会在对应的slot中触发相应的业务逻辑,例如有下面的槽函数:

void MainWindow::on_testCbB_currentIndexChanged(int index) { qDebug() const bool wasBlocked = ui->testCbB->blockSignals(true); ui->testCbB->setCurrentIndex(ui->testCbB->currentIndex() == 0 ? 1 : 0); ui->testCbB->blockSignals(wasBlocked); }

然后点击几次按钮,好了,UI发生了变化,但是并不会产生日志了(即我们为QComboBox连接的on_testCbB_currentIndexChanged()槽函数不会被调用了)。

到了这里,似乎问题已经被彻底解决了。不,再仔细看看,是不是发现这玩意儿跟临界区有那么一点点相似?在我们这个例子中,按钮的处理逻辑非常简单。然而,在实际项目中,处理逻辑肯定比这个复杂得多,一旦程序流程变得复杂,我们就很容易犯错,比如,我们可能调用了ui->testCbB->blockSignals(true)对该控件的信号进行了屏蔽,但是在后续的某个分支处理后或者发生了运行时异常,最终使得我们并没有解除屏蔽就退出了流程,那么该控件后续的所有的信号就都失效了。(这像极了我们使用互斥锁等多线程同步机制时的场景)因此,我们自然而然就想到可以使用RAII( Resource Acquisition Is Initialization)手法来改进这个实现。

等等,先别自己动手造轮子,其实Qt已经提供了这种实现手法,即QSignalBlocker。这个类在Qt 5.3中引入。用法很简单,还是以我们这个场景为例:

void MainWindow::on_testBtn_clicked() { QSignalBlocker blocker(ui->testCbB); // signal blocked ui->testCbB->setCurrentIndex(ui->testCbB->currentIndex() == 0 ? 1 : 0); } // signal resumed

QSignalBlocker blocker(ui->testCbB)等价于下列代码:

const bool wasBlocked = ui->testCbB->blockSignals(true); // signals blocked // do something ... ui->testCbB->blockSignals(wasBlocked); 3. Reference QSignalBlocker Class


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3