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

后端 未结 2 441
名媛妹妹
名媛妹妹 2021-02-01 20:26

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
{
           


        
相关标签:
2条回答
  • 2021-02-01 20:43

    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.

    0 讨论(0)
  • 2021-02-01 20:45

    Disconnect/reconnect syntax

    There are many ways to call disconnect, depending on exactly what you want disconnected. See the QObject documentation page for an explanation of how they work.

    Here's an example using 0 to mean "disconnect all slots."

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

    Or you can specify the exact signal-slot pair to disconnect by copying your 'connect' syntax, like this:

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

    Stopping the timer

    Since you're working with a timer, this may be simpler:

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

    Differences from your original approach:

    • Since you're stopping and restarting the timer, the next time it fires will be interval after your slot function finishes.

    Do you need to do anything special at all?

    In a single-threaded Qt application, if you're already handling a signal, another signal won't "jump in the middle" of that code. Instead it'll be queued up as an even to handle immediately after the current slot returns.

    So perhaps you don't need to stop or disconnect your timer at all.

    Differences from your original approach:

    • If on_btnDownload_clicked takes a while to execute, you might have multiple ReadMyCom events queued up after on_btnDownload_clicked completes. (Note that at this point you'd have an operation that basically "locks up" your GUI for a while anyway; it may make more sense to refactor the function or give it its own thread.)
    0 讨论(0)
提交回复
热议问题