如何在Qt中暂时断开信号与插槽的连接?

时间:2015-02-15 09:54:41

标签: qt signals-slots

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

以下是我的班级声明的一部分:

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);

但它仍然不起作用。那么任何人都可以帮我怎么做?

2 个答案:

答案 0 :(得分:19)

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保持同步。

但是,用法仍然完全相同。

答案 1 :(得分:9)

断开/重新连接语法

有多种方法可以调用断开连接,具体取决于您要断开连接的内容。有关其工作原理的说明,请参阅the QObject documentation page

这是一个使用0表示&#34;断开所有插槽的示例。&#34;

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();
}

与原始方法的差异:

  • 由于您正在停止并重新启动计时器,因此在您的插槽功能完成后,下次触发时将为interval

你需要做任何特别的事吗?

在单线程Qt应用程序中,如果您已经处理过一个信号,那么另一个信号就不会在中间跳转#34;那段代码。相反,它会在当前时隙返回后立即排队等待处理。

因此,您可能根本不需要停止或断开计时器。

与原始方法的差异:

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