How to disconnect a signal with a slot temporarily in Qt?

ctxrr picture ctxrr · Feb 15, 2015 · Viewed 31.8k times · Source

I connect a slot with a signal. But now I want to disconnect them temporarily.

Here is part of my class declaration:

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

In the constructor of frmMain, I connect myReadTimer with a slot so that ReadMyCom will be called every 5 seconds:

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

But, in slot on_btnDownload_clicked. I don't want myReadTimer to emit any signal in on_btnDownload_clicked's scope. So I want to disconnect them at the beginning of on_btnDownload_clicked and reconnect them in the end. Like this:

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
}

I searched in Stackoverflow and got some answer like call the QObject destructor. But I don't know how to use it.

I also tried to use disconnect, like:

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

But it still not work. So could any one help me how to do this?

Answer

RobbieE picture RobbieE · Feb 15, 2015

There is a very nice function in QObject that comes in handy every now and again: QObject::blockSignals()

Here's a very simple fire-and-forget class that will do what you want. I take no credit for it's design, I found it on the internet somewhere a long time ago. Be careful though, it will block all signals to all objects. If this is not what you want, you can modify the class to suit your needs.

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

Usage, in your case, becomes trivial

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
}

UPDATE:

I see that from Qt 5.3, a very similar class has been offically added to the API. It does a similar job as the one above with a slightly bigger feature-set. I suggest you use the official QSignalBlocker class instead in order to keep your codebase up-to-date with any API changes.

Usage, however, remains exactly the same.