【问题标题】:How to disconnect a signal with a slot temporarily in Qt?如何在 Qt 中临时断开与插槽的信号?
【发布时间】:2015-04-15 23:45:25
【问题描述】:

我用信号连接了一个插槽。但现在我想暂时断开它们。

这是我的班级声明的一部分:

class frmMain : public QWidget
{
    ...
private:
    QTimer *myReadTimer;
    ...
private slots:
    void on_btnDownload_clicked();
    ...
};

frmMain 的构造函数中,我将myReadTimer 与一个槽连接,以便每5 秒调用一次ReadMyCom

myReadTimer=new QTimer(this);
myReadTimer->setInterval(5000);
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));

但是,在插槽on_btnDownload_clicked。我不希望myReadTimeron_btnDownload_clicked 的范围内发出任何信号。所以我想在on_btnDownload_clicked的开头断开它们,最后重新连接它们。像这样:

void frmMain::on_btnDownload_clicked()
{
    //some method to disconnect the slot & singal

    ...//the code that I want myReadTimer to leave me alone

    //some method to reconnect the slot & singal
}

我在 Stackoverflow 中搜索并得到了一些答案,例如调用 QObject 析构函数。但我不知道如何使用它。

我也试过用disconnect,比如:

QMetaObject::Connection myConnect;
myConnect=connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
...
disconnect(& myConnect);

但是还是不行。那么任何人都可以帮助我如何做到这一点?

【问题讨论】:

  • 您查看过disconnect 的文档吗?它采用与connect 相同的参数。
  • 我看了disconnect的文档发现static bool disconnect(const QMetaObject::Connection &);那我怎么错了?
  • 您使用 QObject::disconnect() 的示例是正确的,除了该示例在预期引用的位置传递了一个指针 - 所以它甚至不应该编译! disconnect(myConnect) 工作。

标签: qt signals-slots


【解决方案1】:

QObject 中有一个非常好的函数,它时不时地派上用场:QObject::blockSignals()

这是一个非常简单的“即发即弃”类,它可以满足您的需求。我不相信它的设计,我很久以前在互联网上的某个地方找到了它。但要小心,它会阻止所有对象的所有信号。如果这不是您想要的,您可以修改该类以满足您的需要。

class SignalBlocker{
public:
    SignalBlocker(QObject *o): object(o), alreadyBlocked(object->signalsBlocked()){
        if (!alreadyBlocked){
            object->blockSignals(true);
        }
    }
    ~SignalBlocker() {
        if (!alreadyBlocked){
            object->blockSignals(false);
        }
    }

private:
    QObject *object;
    bool alreadyBlocked;
};

在你的情况下,使用变得微不足道

void frmMain::on_btnDownload_clicked()
{
    SignalBlocker timerSignalBlocker(myReadTimer);

    ...//the code that I want myReadTimer to leave me alone

    // signals automatically unblocked when the function exits
}

更新:

我看到从 Qt 5.3 开始,一个非常相似的类被正式添加到 API 中。它的功能与上面的类似,但功能集稍大。我建议您改用官方的 QSignalBlocker 类,以使您的代码库在任何 API 更改时保持最新。

但是,用法保持不变。

【讨论】:

    【解决方案2】:

    断开/重新连接语法

    有很多方法可以调用断开连接,具体取决于您想要断开连接的具体内容。请参阅 the QObject documentation page 了解它们的工作原理。

    这是一个使用 0 表示“断开所有插槽”的示例。

    void frmMain::on_btnDownload_clicked()
    {
        // disconnect everything connected to myReadTimer's timeout
        disconnect(myReadTimer, SIGNAL(timeout()), 0, 0);    
    
        ...//the code that I want myReadTimer to leave me alone
    
        // restore the connection
        connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
    }
    

    或者您可以通过复制“连接”语法来指定要断开连接的确切信号槽对,如下所示:

    disconnect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
    

    停止计时器

    由于您使用的是计时器,这可能更简单:

    void frmMain::on_btnDownload_clicked()
    {
        // stop the timer (so you won't get any timeout signals)
        myReadTimer->stop();    
    
        ...//the code that I want myReadTimer to leave me alone
    
        // restart the timer (using whatever interval was set previously)
        myReadTimer->start();
    }
    

    与您原来的方法的不同之处:

    • 由于您正在停止并重新启动计时器,因此在您的 slot 函数完成后,它的下一次触发将是 interval

    您需要做一些特别的事情吗?

    在单线程 Qt 应用程序中,如果您已经在处理一个信号,则另一个信号不会“跳到”该代码的中间。相反,它会在当前槽返回后立即排队处理。

    所以也许您根本不需要停止或断开计时器。

    与您原来的方法的不同之处:

    • 如果on_btnDownload_clicked 需要一段时间才能执行,那么在on_btnDownload_clicked 完成后,您可能会有多个ReadMyCom 事件排队。 (请注意,此时您的操作基本上会“锁定”您的 GUI 一段时间;重构函数或给它自己的线程可能更有意义。)

    【讨论】:

      猜你喜欢
      • 2019-02-12
      • 2014-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多