Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QDoubleSpinBox - blockSignals() does not work

QDoubleSpinBox - blockSignals() does not work

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 5 Posters 1.9k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    DL5EU
    wrote on last edited by
    #5

    This works, but if it is a hack, it is perhaps not the best solution.

    What I would like to achieve in my program is to detect when a user has modified the content of the spin box and to distinguish this from a call to "setValue()". I thought I could use QObject's "setModified()" method whenever the value is changed and just block the signals before calling "setValue()" so that this does not trigger the emission of the "valueChanged()" signal.

    Is there a better way to do this? If yes, could you please let me know? I am no Qt expert...

    Thanks.

    J.HilkJ 1 Reply Last reply
    0
    • D DL5EU

      This works, but if it is a hack, it is perhaps not the best solution.

      What I would like to achieve in my program is to detect when a user has modified the content of the spin box and to distinguish this from a call to "setValue()". I thought I could use QObject's "setModified()" method whenever the value is changed and just block the signals before calling "setValue()" so that this does not trigger the emission of the "valueChanged()" signal.

      Is there a better way to do this? If yes, could you please let me know? I am no Qt expert...

      Thanks.

      J.HilkJ Online
      J.HilkJ Online
      J.Hilk
      Moderators
      wrote on last edited by J.Hilk
      #6

      @DL5EU I would subclass QDoubleSpinbox and make my own, better suited one:

      #include <QApplication>
      #include <QDebug>
      #include <QTimer>
      #include <QDoubleSpinBox>
      
      class MyDoubleSpinBox : public QDoubleSpinBox
      {
          Q_OBJECT
      
      public:
          MyDoubleSpinBox(QWidget*parent = nullptr) : QDoubleSpinBox(parent)
          {
              connect(this, QOverload<double>::of(&MyDoubleSpinBox::valueChanged), this, &MyDoubleSpinBox::onValueChanged);
          }
      
          //new setter
          void setValueByCode(double value){
              m_changedByCode = true;
              setValue(value);
          }
      
      signals:
          void valueChangedByUser(double value);
          void valueChangedByCode(double value);
      
      private slots:
          void onValueChanged(double value){
              if(m_changedByCode)
                  emit valueChangedByCode(value);
              else
                  emit valueChangedByUser(value);
              m_changedByCode = false;
          }
      
      private:
          bool m_changedByCode{false};
      
      };
      
      int main(int argc, char *argv[])
      {
          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
          QApplication app(argc, argv);
      
          MyDoubleSpinBox mdsb;
      
          //Test: automatically set value by code via timer
          QTimer t;
          QObject::connect(&t, &QTimer::timeout, [&]()->void{mdsb.setValueByCode(mdsb.value()+1);});
          
          //see, if it was changed by hand or by program
          QObject::connect(&mdsb, &MyDoubleSpinBox::valueChangedByCode, [](double value)->void{qDebug() << "value by code" << value;});
          QObject::connect(&mdsb, &MyDoubleSpinBox::valueChangedByUser, [](double value)->void{qDebug() << "value by user" << value;});
      
          t.start(5000);
          mdsb.show();
          return app.exec();
      
      }
      
      #include "main.moc"
      

      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      D 1 Reply Last reply
      2
      • D Offline
        D Offline
        DL5EU
        wrote on last edited by
        #7

        That is of course a solution but I thought I could avoid subclassing QDoubleSpinBox. The more you can use existing components the less code you have to maintain. However, I think I will try this way.

        Thank you very much,

        Ralf

        1 Reply Last reply
        1
        • D Offline
          D Offline
          DL5EU
          wrote on last edited by
          #8

          I have noticed that when I subclass QDoubleSpinBox as proposed, the first modification by the user is not recognised as such. This is probably due to the original problem, i.e. that the valueChanged() signal is not processed. In Qt Creator in debug mode I can see that the setter is entered but not the onValueChanged() method of my new object (in response to the call to setValueByCode()). That is the reason why m_changedByCode is still true when onValueChanged() is entered in repsponse to a modification done by the user.

          This is what the code of my new double spin box looks like:

          .h file:

          class GDoubleSpinBox : public QDoubleSpinBox
          {
              Q_OBJECT
          public:
              explicit GDoubleSpinBox(QWidget *parent = nullptr);
          public slots:
              void setValueByCode(double value);
          signals:
              void valueChangedByCode(double value);
              void valueChangedByUser(double value);
          private:
              bool m_changedByCode;
          private slots:
              void onValueChanged(double value);
          };
          
          

          .cpp file:

          GDoubleSpinBox::GDoubleSpinBox(QWidget *parent)
              : QDoubleSpinBox(parent)
              , m_changedByCode(false)
          {
              connect(this, QOverload<double>::of(&GDoubleSpinBox::valueChanged), this, &GDoubleSpinBox::onValueChanged);
          }
          
          void GDoubleSpinBox::setValueByCode(double value)
          {
              m_changedByCode = true;
              setValue(value);
          }
          
          void GDoubleSpinBox::onValueChanged(double value)
          {
              if (m_changedByCode) {
                  emit valueChangedByCode(value);
              }
              else {
                  emit valueChangedByUser(value);
              }
              m_changedByCode = false;
          }
          
          

          Any idea?

          J.HilkJ JonBJ 2 Replies Last reply
          0
          • D DL5EU

            I have noticed that when I subclass QDoubleSpinBox as proposed, the first modification by the user is not recognised as such. This is probably due to the original problem, i.e. that the valueChanged() signal is not processed. In Qt Creator in debug mode I can see that the setter is entered but not the onValueChanged() method of my new object (in response to the call to setValueByCode()). That is the reason why m_changedByCode is still true when onValueChanged() is entered in repsponse to a modification done by the user.

            This is what the code of my new double spin box looks like:

            .h file:

            class GDoubleSpinBox : public QDoubleSpinBox
            {
                Q_OBJECT
            public:
                explicit GDoubleSpinBox(QWidget *parent = nullptr);
            public slots:
                void setValueByCode(double value);
            signals:
                void valueChangedByCode(double value);
                void valueChangedByUser(double value);
            private:
                bool m_changedByCode;
            private slots:
                void onValueChanged(double value);
            };
            
            

            .cpp file:

            GDoubleSpinBox::GDoubleSpinBox(QWidget *parent)
                : QDoubleSpinBox(parent)
                , m_changedByCode(false)
            {
                connect(this, QOverload<double>::of(&GDoubleSpinBox::valueChanged), this, &GDoubleSpinBox::onValueChanged);
            }
            
            void GDoubleSpinBox::setValueByCode(double value)
            {
                m_changedByCode = true;
                setValue(value);
            }
            
            void GDoubleSpinBox::onValueChanged(double value)
            {
                if (m_changedByCode) {
                    emit valueChangedByCode(value);
                }
                else {
                    emit valueChangedByUser(value);
                }
                m_changedByCode = false;
            }
            
            

            Any idea?

            J.HilkJ Online
            J.HilkJ Online
            J.Hilk
            Moderators
            wrote on last edited by
            #9

            @DL5EU I can't see any obvious problems,

            But my example is a compile ready one (you just throw it into a main.cpp and hit compile) and when I test it there, the first edit by a use is registered as an edit by the user.

            Have you tried your class in a standalone project to verify it works as expected? It my be an other part of your code, thats the issue here


            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            1 Reply Last reply
            0
            • D DL5EU

              I have noticed that when I subclass QDoubleSpinBox as proposed, the first modification by the user is not recognised as such. This is probably due to the original problem, i.e. that the valueChanged() signal is not processed. In Qt Creator in debug mode I can see that the setter is entered but not the onValueChanged() method of my new object (in response to the call to setValueByCode()). That is the reason why m_changedByCode is still true when onValueChanged() is entered in repsponse to a modification done by the user.

              This is what the code of my new double spin box looks like:

              .h file:

              class GDoubleSpinBox : public QDoubleSpinBox
              {
                  Q_OBJECT
              public:
                  explicit GDoubleSpinBox(QWidget *parent = nullptr);
              public slots:
                  void setValueByCode(double value);
              signals:
                  void valueChangedByCode(double value);
                  void valueChangedByUser(double value);
              private:
                  bool m_changedByCode;
              private slots:
                  void onValueChanged(double value);
              };
              
              

              .cpp file:

              GDoubleSpinBox::GDoubleSpinBox(QWidget *parent)
                  : QDoubleSpinBox(parent)
                  , m_changedByCode(false)
              {
                  connect(this, QOverload<double>::of(&GDoubleSpinBox::valueChanged), this, &GDoubleSpinBox::onValueChanged);
              }
              
              void GDoubleSpinBox::setValueByCode(double value)
              {
                  m_changedByCode = true;
                  setValue(value);
              }
              
              void GDoubleSpinBox::onValueChanged(double value)
              {
                  if (m_changedByCode) {
                      emit valueChangedByCode(value);
                  }
                  else {
                      emit valueChangedByUser(value);
                  }
                  m_changedByCode = false;
              }
              
              

              Any idea?

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #10

              @DL5EU said in QDoubleSpinBox - blockSignals() does not work:

              In Qt Creator in debug mode I can see that the setter is entered but not the onValueChanged() method of my new object

              I cannot be sure whether this is your case but: Assuming you mean you placed a breakpoint and run under debugger, you will find that does not work right on a spin box. I discovered this (at great cost!) a while ago. It is because QSpinBox::onValueChanged() uses an internal timer to do its work, and when you slow things down by debugging it "breaks" how it works.

              Here is the way I wrote to connect the QSpinBox::valueChanged() signal so that I can break in the debugger if necessary:

              template <typename Context, typename Method>
                  QMetaObject::Connection connectSpinBoxValueChanged(QSpinBox *spin, Context slotObject, Method method)
                  {
                      // connect `spin->valueChanged(int i)` signal to slot
                      // see https://forum.qt.io/topic/113606/qspinbox-valuechanged-with-debugger-breakpoint-brain-damaged and https://bugreports.qt.io/browse/QTBUG-14259
                      // for why `Qt::QueuedConnection` is specified here
                      return QObject::connect(spin, QOverload<int>::of(&QSpinBox::valueChanged), slotObject, method, Qt::QueuedConnection);
                  }
              

              which is what I now use, whether debugging or not. You can read up on the whys & wherefores in my https://forum.qt.io/topic/113606/qspinbox-valuechanged-with-debugger-breakpoint-brain-damaged and https://bugreports.qt.io/browse/QTBUG-14259.

              1 Reply Last reply
              0
              • D Offline
                D Offline
                DL5EU
                wrote on last edited by
                #11

                No, I have not tried it stand alone yet but I will do so later this day.

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  DL5EU
                  wrote on last edited by
                  #12

                  Thanks @JonB, I will try this too.

                  1 Reply Last reply
                  0
                  • jeremy_kJ Offline
                    jeremy_kJ Offline
                    jeremy_k
                    wrote on last edited by jeremy_k
                    #13

                    This works for me, with Qt 5.15.5 on macOS

                    #include <QtGlobal>
                    #include <QVBoxLayout>
                    #include <QWidget>
                    #include <QApplication>
                    #include <QDoubleSpinBox>
                    #include <QPushButton>
                    #include <QDebug>
                    
                    int main(int argc, char *argv[])
                    {
                        QApplication a(argc, argv);
                    
                        QDoubleSpinBox *box = new QDoubleSpinBox;
                        QPushButton *button = new QPushButton(box->signalsBlocked() ? "true" : "false");
                        QObject::connect(button, &QPushButton::clicked, [box, button]() {
                            bool isBlocked = box->signalsBlocked();
                            box->blockSignals(!isBlocked);
                            button->setText(!isBlocked ? "true" : "false");
                        });
                        QObject::connect(box, qOverload<double>(&QDoubleSpinBox::valueChanged), [](double value) { qDebug() << "value" << value; });
                    
                        QPushButton *button2 = new QPushButton("set to 1.0");
                        QObject::connect(button2, &QPushButton::clicked, [box](){ box->setValue(1.0);});
                    
                        QWidget container;
                        QVBoxLayout layout(&container);
                        layout.addWidget(box);
                        layout.addWidget(button);
                        layout.addWidget(button2);
                        container.show();
                    
                        return a.exec();
                    }
                    

                    When button reads "true", using the spinbox or clicking button2 does not result in a debug message. When button reads "false", the spinbox controls generate debug output, and if the value isn't already 1.0, clicking button2 also generates output.

                    I suspect something else is going on.

                    Asking a question about code? http://eel.is/iso-c++/testcase/

                    1 Reply Last reply
                    0
                    • J.HilkJ J.Hilk

                      @DL5EU I would subclass QDoubleSpinbox and make my own, better suited one:

                      #include <QApplication>
                      #include <QDebug>
                      #include <QTimer>
                      #include <QDoubleSpinBox>
                      
                      class MyDoubleSpinBox : public QDoubleSpinBox
                      {
                          Q_OBJECT
                      
                      public:
                          MyDoubleSpinBox(QWidget*parent = nullptr) : QDoubleSpinBox(parent)
                          {
                              connect(this, QOverload<double>::of(&MyDoubleSpinBox::valueChanged), this, &MyDoubleSpinBox::onValueChanged);
                          }
                      
                          //new setter
                          void setValueByCode(double value){
                              m_changedByCode = true;
                              setValue(value);
                          }
                      
                      signals:
                          void valueChangedByUser(double value);
                          void valueChangedByCode(double value);
                      
                      private slots:
                          void onValueChanged(double value){
                              if(m_changedByCode)
                                  emit valueChangedByCode(value);
                              else
                                  emit valueChangedByUser(value);
                              m_changedByCode = false;
                          }
                      
                      private:
                          bool m_changedByCode{false};
                      
                      };
                      
                      int main(int argc, char *argv[])
                      {
                          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                          QApplication app(argc, argv);
                      
                          MyDoubleSpinBox mdsb;
                      
                          //Test: automatically set value by code via timer
                          QTimer t;
                          QObject::connect(&t, &QTimer::timeout, [&]()->void{mdsb.setValueByCode(mdsb.value()+1);});
                          
                          //see, if it was changed by hand or by program
                          QObject::connect(&mdsb, &MyDoubleSpinBox::valueChangedByCode, [](double value)->void{qDebug() << "value by code" << value;});
                          QObject::connect(&mdsb, &MyDoubleSpinBox::valueChangedByUser, [](double value)->void{qDebug() << "value by user" << value;});
                      
                          t.start(5000);
                          mdsb.show();
                          return app.exec();
                      
                      }
                      
                      #include "main.moc"
                      
                      D Offline
                      D Offline
                      DL5EU
                      wrote on last edited by
                      #14

                      @J-Hilk: I have tried to compile your program in Qt Creator but main.moc is missing and without it it does not compile. As I wrote, I am no Qt expert and I am used to develop in Qt Creator where I don't have to create .moc files myself. I will set up a project with your code as soon as I have got the time (in a week).

                      @jeremy_k: your program works as described. Perhaps there is a problem elsewhere that I don't see yet. I will check this when I am back from holidays.

                      J.HilkJ D 2 Replies Last reply
                      0
                      • D DL5EU

                        @J-Hilk: I have tried to compile your program in Qt Creator but main.moc is missing and without it it does not compile. As I wrote, I am no Qt expert and I am used to develop in Qt Creator where I don't have to create .moc files myself. I will set up a project with your code as soon as I have got the time (in a week).

                        @jeremy_k: your program works as described. Perhaps there is a problem elsewhere that I don't see yet. I will check this when I am back from holidays.

                        J.HilkJ Online
                        J.HilkJ Online
                        J.Hilk
                        Moderators
                        wrote on last edited by J.Hilk
                        #15

                        @DL5EU said in QDoubleSpinBox - blockSignals() does not work:

                        Creator but main.moc is missing and without it it does not compile.

                        it‘s auto generated by qmake, its missing on the first compile, if not explicitly set up in the pro file.

                        simply hit compile a 2nd time, and it should work.


                        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                        Q: What's that?
                        A: It's blue light.
                        Q: What does it do?
                        A: It turns blue.

                        1 Reply Last reply
                        0
                        • D DL5EU

                          @J-Hilk: I have tried to compile your program in Qt Creator but main.moc is missing and without it it does not compile. As I wrote, I am no Qt expert and I am used to develop in Qt Creator where I don't have to create .moc files myself. I will set up a project with your code as soon as I have got the time (in a week).

                          @jeremy_k: your program works as described. Perhaps there is a problem elsewhere that I don't see yet. I will check this when I am back from holidays.

                          D Offline
                          D Offline
                          DL5EU
                          wrote on last edited by
                          #16

                          @J-Hilk I had the time now to try out your example. It works indeed as expected. There must be something in my code that prevents the application from working as expected, perhaps a side effect of something that I have not found yet. I will further investigate.

                          Ralf

                          1 Reply Last reply
                          1

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved