防止在 Qt 中触发信号

在 Qt 中工作时,有时我们需要暂时阻止某些信号的触发。以下是一个经典场景:我们有一个 QCheckBox 对象,当用户勾选或取消勾选时,需要调用一个函数,因此我们将这个函数连接到 stateChanged(int state) 信号。然而,在某些条件下,我们在代码中更改 QCheckBox 的状态,这会导致触发不需要的信号。那么如何在特定情况下防止信号触发呢?

使用 clicked 信号

如果你只想在用户实际点击复选框时触发信号,可以使用 clicked 信号,因为这个信号只在用户点击复选框时触发,而不会在代码中使用 setChecked 方法更改状态时触发。

使用 QObject::blockSignals

你可以使用 QObject::blockSignals 方法来暂时阻止信号的发射:

cpp 复制代码
bool oldState = checkBox->blockSignals(true);
checkBox->setChecked(true);
checkBox->blockSignals(oldState);

这种方法的缺点是它会阻止所有信号的发射,但对于 QCheckBox 来说,这通常不是什么大问题。

使用 RAII 封装 blockSignals

为了更好地管理信号阻塞,可以使用 RAII(资源获取即初始化)模式。以下是一个示例类:

cpp 复制代码
class SignalBlocker
{
public:
    SignalBlocker(QObject *obj) : m_obj(obj), m_old(obj->blockSignals(true)) {}
    ~SignalBlocker() { m_obj->blockSignals(m_old); }

private:
    QObject *m_obj;
    bool m_old;
};

使用这个类,阻塞和恢复信号变得更加自动化和安全,特别是在异常处理的情况下。

使用 Qt5.3 引入的 QSignalBlocker

从 Qt5.3 开始,引入了 QSignalBlocker 类,可以简化信号的阻塞:

cpp 复制代码
if (something) {
   const QSignalBlocker blocker(someQObject);
   // 在这里不会发射信号
}

这个类不仅方便而且异常安全。

对多个对象进行信号阻塞

如果需要同时对多个对象进行信号阻塞,可以扩展 SignalBlocker 类:

cpp 复制代码
class SignalBlocker
{
public:
    SignalBlocker(QObject *obj) {
        insert(QList<QObject*>() << obj);
    }
    SignalBlocker(QList<QObject*> objects) {
        insert(objects);
    }
    void insert(QList<QObject*> objects) {
        for (auto obj : objects)
            m_objs.insert(obj, obj->signalsBlocked());
        blockAll();
    }
    void blockAll() {
        for(auto m_obj : m_objs.keys())
            m_obj->blockSignals(true);
    }
    ~SignalBlocker() {
        for(auto m_obj : m_objs.keys())
            m_obj->blockSignals(m_objs[m_obj]);
    }

private:
    QMap<QObject*,bool> m_objs;
};

使用示例:

cpp 复制代码
void SomeType::myFunction() {
    SignalBlocker blocker(QList<QObject*>()
                          << m_paramWidget->radioButton_View0
                          << m_paramWidget->radioButton_View1
                          << m_paramWidget->radioButton_View2);
    // 执行其他操作
}

通过这些方法,你可以灵活地管理 Qt 应用程序中的信号阻塞,从而避免不必要的信号触发。

相关推荐
这个DBA有点耶38 分钟前
DELETE没删多少数据,表却越来越大——InnoDB删除空洞与页合并失效的根因
数据库·mysql·代码规范
WJ.Polar4 小时前
Java封装、继承、多态
java·开发语言
ly76894 小时前
PostgreSQL 备份恢复策略:pg_basebackup、WAL 归档与 PITR 在企业 Java 系统中的落地
java·数据库·postgresql·pitr·pg_basebackup·wal 归档
摇滚侠4 小时前
Java 中如何表示负数,有符号和无符号的区别,补码的计算规则,char byte short int long 的范围
java·开发语言
weixin_307779134 小时前
C++代码实现MATLAB中的fitrtree函数功能
开发语言·c++·算法·matlab
爱读书的小胖4 小时前
Codewars:Rot13(C)解题分析
c语言·开发语言
小羊没烦恼!5 小时前
Ajax与JSON的一些总结
android·java·前端·数据库·mysql·算法·okhttp
鸽鸽程序猿5 小时前
【项目】【在线判题系统】b端题目增删改
开发语言·python
注塑机数据采集联网5 小时前
如何解决注塑机数据采集联网对接MES系统数据WiFi传输数据不稳问题
大数据·数据库·物联网·数据挖掘·数据分析
Lhappy嘻嘻5 小时前
读懂 JVM:内存模型、类加载机制、分代回收
java·开发语言·jvm