Подтвердить что ты не робот

Как временно отключить сигнал с временным интервалом в Qt?

Я подключаю слот с сигналом. Но теперь я хочу временно отключить их.

Вот часть моего объявления класса:

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

В конструкторе frmMain я соединяю myReadTimer со слотом, так что ReadMyCom будет вызываться каждые 5 секунд:

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

Но в слоте on_btnDownload_clicked. Я не хочу, чтобы myReadTimer излучал любой сигнал в области on_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);

Но он все еще не работает. Так может ли кто-нибудь помочь мне, как это сделать?

4b9b3361

Ответ 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
}

UPDATE:

Я вижу, что из Qt 5.3 в API был добавлен очень похожий класс. Он выполняет ту же работу, что и выше, с чуть большим набором функций. Я предлагаю вам использовать официальный QSignalBlocker класс, чтобы обновлять свою кодовую базу с любыми изменениями API.

Использование, однако, остается тем же самым.

Ответ 2

Синтаксис разъединения/повторного подключения

Существует много способов вызвать разъединение, в зависимости от того, что вы хотите отключить. См. страницу документации QObject для объяснения того, как они работают.

Здесь пример с использованием 0 означает "отключить все слоты".

void frmMain::on_btnDownload_clicked()
{
    // disconnect everything connected to myReadTimer 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()));
}

Или вы можете указать точную пару сигнальных слотов для отключения, скопировав синтаксис "connect", например:

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, если вы уже обрабатываете сигнал, другой сигнал не будет "посередине" этого кода. Вместо этого он будет стоять в очереди, как даже обрабатывать сразу после возвращения текущего слота.

Поэтому, возможно, вам не нужно вообще останавливать или отключать ваш таймер.

Отличия от вашего первоначального подхода:

  • Если для выполнения on_btnDownload_clicked требуется некоторое время, вы можете иметь несколько событий ReadMyCom в очереди после завершения on_btnDownload_clicked. (Обратите внимание, что на данном этапе у вас будет операция, которая в любом случае "закроет" ваш графический интерфейс в любом случае, может быть больше смысла реорганизовать функцию или дать ей собственный поток.) ​​