Search code examples
qtsignalsqobject

What is the right way to suppress Qt signals when values are explicitely set


I got a from QWidget derived class that holds three QSpinBoxes (e.g. coordinates). The valueChanged() signal is connected and is emitted in at least these three cases:

  1. up/down button
  2. manually entered number
  3. setValue()

However, when using setValue(), I want to suppress the signal(s), since I don't want to have (three) signals. In my understanding, there are two ways to handle this:

  1. QObject::blockSignals()
  2. using a flag that indicates whether the values were explicitely set

Both variants work, but I think they are not straight-forward at all: For the first one, I generally block all signals AND I need to set blockSignals(true) for all underyling widgets (blockSignals doesn't block children QObjects in my application). For the second one, I need to query the flag in every update method AND the signals are raised although I don't need them.

Are there any general designing patterns that prevent such behavior? If not, what variant would you prefer?


Solution

  • The third option would be to subclass QSpinBox, implement desired functionality there, and used derived class instead of QSpinBox - this hides all associated complexity in derived class and allows you use it just like QSpinBox.

    For example, following class

    myQSpinBox.h

    #ifndef MYQSPINBOX_H
    #define MYQSPINBOX_H
    
    #include <QSpinBox>
    
    class myQSpinBox : public QSpinBox
    {
        Q_OBJECT
    public:
        myQSpinBox(QWidget * parent = 0 );
    protected:
        bool valueBeingSet;
    public slots:
        void setValue (int val);
    private slots:
        void On_valueChanged(int val);
    signals:
        void valueChangedNotBySet(int val);
    };
    
    #endif // MYQSPINBOX_H
    

    myQSpinBox.cpp

    #include "myQSpinBox.h"
    
    myQSpinBox::myQSpinBox(QWidget * parent)
            : QSpinBox(parent)
            , valueBeingSet(false)
    {
        connect(this,SIGNAL(valueChanged(int)),this,SLOT(On_valueChanged(int)));
    }
    
    void    myQSpinBox::setValue ( int val )
    {
        valueBeingSet = true;
        QSpinBox::setValue(val);
        valueBeingSet = false;
    }
    
    void myQSpinBox::On_valueChanged(int val)
    {
        if(!valueBeingSet)
            emit valueChangedNotBySet(val);
    }
    

    will emit valueChangedNotBySet(int); in cases 1. and 2., but not in case 3., keeping all QSpinBox functionality intact