Prevent Firing Signals in Qt

前端 未结 8 958
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-14 14:07

We have a QCheckBox object, when user checks it or removes check we want to call a function so we connect our function to stateChanged ( int state )

相关标签:
8条回答
  • 2020-12-14 14:48

    You can always block signal emission on QObjects using QObject::blockSignals(). Note that to be correct about things, you should remember the old state (returned from the function call), and restore it when you are done.

    At my job, we prefer RAII for this sort of thing. A simple class to do so might look like this:

    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: Starting with Qt 5.3, see QSignalBlocker (h/t to HappyCactus in comments)

    0 讨论(0)
  • 2020-12-14 14:48

    While learning Qt, I ran into this problem with a set of interconnected widgets that I wanted to update "atomically". I liked @cjhuitt's solution, but found that it goes even better with a bit of syntactic sugar based on proxy objects. Here's the approach that I used...

    First, I defined a class template for a blocker proxy object. Like Caleb's, this blocks the signals on construction, and then restores their previous state on destruction. However, it also overloads the -> operator to return a pointer to the blocked object:

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

    Next, I defined a small template function to construct and return a Blocker:

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

    Putting this all together, I'd use it like this:

    whileBlocking(checkBox)->setChecked(true);
    

    or

    whileBlocking(xyzzySpin)->setValue(50);
    

    This gets me all the benefits of RAII, with automatically paired blocking and restore around the method call, but I don't need to name any wrapper or state flags. It's nice, easy, and pretty darn foolproof.

    0 讨论(0)
提交回复
热议问题