Prévenir les signaux de tir dans Qt

Nous avons un object QCheckBox , lorsque l’utilisateur le vérifie ou supprime la vérification, nous voulons appeler une fonction pour connecter notre fonction au stateChanged ( int state ) . D’autre part, selon certaines conditions, nous modifions également l’état de l’object QCheckBox dans le code, ce qui provoque le signal indésirable.

Y a-t-il un moyen d’empêcher le signal de tir dans certaines conditions?

    Vous pouvez utiliser le signal clicked car il est émis uniquement lorsque l’utilisateur clique sur la case à cocher, et non lorsque vous le cochez manuellement avec setChecked .

    Si vous ne voulez pas que le signal soit émis à un moment précis, vous pouvez utiliser QObject::blockSignals comme ceci:

     bool oldState = checkBox->blockSignals(true); checkBox->setChecked(true); checkBox->blockSignals(oldState); 

    L’inconvénient de cette approche est que tous les signaux seront bloqués. Mais je suppose que cela n’a pas vraiment d’importance en cas de QCheckBox .

    Vous pouvez toujours bloquer l’émission du signal sur les QObjects en utilisant QObject::blockSignals() . Notez que pour être correct sur les choses, vous devez vous souvenir de l’ancien état (renvoyé par l’appel de la fonction) et le restaurer lorsque vous avez terminé.

    À mon travail, nous préférons RAII pour ce genre de chose. Une simple classe à faire pourrait ressembler à ceci:

     class SignalBlocker { public: SignalBlocker( QObject *obj ) : m_obj( obj ), m_old( obj->blockSignals( true ) ) { } ~SignalBlocker() { m_obj->blockSignals( m_old ); } private: QObject *m_obj; bool m_old; }; 

    Edit : à partir de Qt 5.3, voir QSignalBlocker (h / t à HappyCactus dans les commentaires)

    Vous pouvez QObject::disconnect pour supprimer la connexion signal-slot correspondante et peut QObject::connect une fois que vous avez terminé …

    Tout en apprenant Qt, j’ai rencontré ce problème avec un ensemble de widgets interconnectés que je voulais mettre à jour de manière “atomique”. J’ai bien aimé la solution de @ cjhuitt, mais j’ai trouvé que ça allait encore mieux avec un peu de sucre syntaxique basé sur des objects proxy . Voici l’approche que j’ai utilisée …

    Tout d’abord, j’ai défini un modèle de classe pour un object proxy de bloqueur. Comme Caleb, cela bloque les signaux lors de la construction, puis restaure leur état antérieur lors de la destruction. Cependant, il surcharge également l’opérateur -> pour renvoyer un pointeur sur l’object bloqué:

     template class Blocker { T *blocked; bool previous; public: Blocker(T *blocked) : blocked(blocked), previous(blocked->blockSignals(true)) {} ~Blocker() { blocked->blockSignals(previous); } T *operator->() { return blocked; } }; 

    Ensuite, j’ai défini une fonction de petit modèle pour construire et renvoyer un bloqueur:

     template inline Blocker whileBlocking(T *blocked) { return Blocker(blocked); } 

    En mettant tout cela ensemble, je l’utilise comme ceci:

     whileBlocking(checkBox)->setChecked(true); 

    ou

     whileBlocking(xyzzySpin)->setValue(50); 

    Cela me procure tous les avantages de RAII, avec le blocage et la restauration automatiquement couplés autour de l’appel de méthode, mais je n’ai pas besoin de nommer de drapeaux de wrapper ou d’état. C’est sympa, facile et pas mal infaillible.

    Dans les classes dérivées QObject , vous pouvez appeler blockSignals(bool) pour empêcher l’object d’émettre des signaux. Donc par exemple:

     void customChangeState(bool checked) { blockSignals(true); ui->checkBox->setCheckState(Qt::Checked); // other work blockSignals(false); } 

    La méthode ci-dessus changerait l’état de vérification sans clic, stateChanged ou tout autre signal émis.

    Qt5.3 a introduit la classe QSignalBlocker qui fait exactement ce dont elle a besoin d’une manière sûre.

     if (something) { const QSignalBlocker blocker(someQObject); // no signals here } 

    Même dans QT5, c’est un peu lourd quand il y a beaucoup de choses à bloquer. Voici une version multi-objects concise à utiliser:

     class SignalBlocker { public: SignalBlocker(QObject *obj) { insert( QList()< objects) { insert(objects); } void insert(QList objects) { for (auto obj : objects) m_objs.insert(obj, obj->signalsBlocked()); blockAll(); } void blockAll() { for( auto m_obj : m_objs.keys() ) m_obj->blockSignals(true); } ~SignalBlocker() { for( auto m_obj : m_objs.keys() ) m_obj->blockSignals( m_objs[m_obj] ); } private: QMap m_objs; }; 

    usage:

     void SomeType::myFunction() { SignalBlocker tmp( QList() << m_paramWidget->radioButton_View0 << m_paramWidget->radioButton_View1 << m_paramWidget->radioButton_View2 ); // Do more work, ... } 

    Si un élément de l’interface utilisateur ne répond pas à l’utilisateur, il convient de le désactiver. Pour que l’utilisateur sache que cet élément n’accepte pas les entrées.