Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Issues setting value of QDoubleSpinBox after connecting



  • valuesetter.h:

    #ifndef VALUESETTER_H
    #define VALUESETTER_H
    
    #include <QSlider>
    #include <QSpinBox>
    #include <QWidget>
    #include <memory>
    
    namespace Ui {
    class ValueSetter;
    }
    
    class ValueSetter : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit ValueSetter(QWidget *parent = nullptr);
        ~ValueSetter();
    
        void dpi(int dpi);
        void setValue(int value);
        void setDoubleValue(double value);
        void setMinimum(int minimum);
        void setMaximum(int maximum);
    
    signals:
        void valueChanged(int);
        void valueChangedDouble(double);
        void minimumChanged(int);
        void maximumChanged(int);
    
    private:
        double round2(double val);
        int val, min, max;
    
        int Dpi=72;
        Ui::ValueSetter *ui;
    };
    
    #endif // VALUESETTER_H
    

    valuesetter.cpp:

    #include "valuesetter.h"
    #include "ui_valuesetter.h"
    
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    #include <string>
    #include <QtMath>
    #include <QDebug>
    
    ValueSetter::ValueSetter(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::ValueSetter)
    {
        ui->setupUi(this);
        setValue(0); setMinimum(0); setMaximum(1000*Dpi);
        connect(ui->slider,&QSlider::valueChanged,this,&ValueSetter::setValue);
        connect(ui->spinbox,static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
                this,&ValueSetter::setDoubleValue);
    }
    
    ValueSetter::~ValueSetter()
    {
        delete ui;
    }
    
    void ValueSetter::setValue(int value)
    {
        qDebug() << ui->spinbox->maximum() << round2(round2(value)/round2(Dpi));
        ui->spinbox->setValue(round2(round2(value)/round2(Dpi)));
        ui->slider->setValue(value);
        emit valueChanged(value);
    }
    
    void ValueSetter::setDoubleValue(double value)
    {
        ui->spinbox->setValue(value); ui->slider->setValue(static_cast<int>(value*Dpi));
        emit valueChangedDouble(value);
    }
    
    void ValueSetter::setMinimum(int min)
    {
        ui->spinbox->setMinimum(static_cast<double>(min)/Dpi); ui->slider->setMinimum(min);
        emit minimumChanged(min);
    }
    
    void ValueSetter::setMaximum(int max)
    {
        ui->spinbox->setMaximum(static_cast<double>(max)/Dpi); ui->slider->setMaximum(max); emit maximumChanged(max);
    }
    
    double ValueSetter::round2(double val)
    {
        double value = static_cast<int>(100*val+0.5);
        return static_cast<double>(value/100);
    }
    

    valuesetter.ui:
    ValueSetterWidgets.png ValueSetterUI.png

    In short, my problem is that when I try to move the QSlider, I get this set of errors, which I have a hard time resolving:
    ValueSetterDebug.png

    At first, the round2 in my valuesetter.cpp class was simply static_cast<double>. My guess was to test whether the error remained when I made sure there were only 2 decimal places, and it did. I don't think I implemented connect wrong, as there were no compiler errors or anything.

    So I need help debugging.


  • Lifetime Qt Champion

    I would guess it's a stack overflow since QDoubleSpinBox::setValue() triggers QSlider::valueChanged. Take a look at the next calls by clicking on '<More>' and you'll see it.



  • Yes as @Christian-Ehrlicher says, it's overflowing :-( because the signals you connect to (the 2 valueChanged()) can be triggered either by a human clicking on the slider or the spinbox, or by your C++ code doing a ->setValue().

    So when you drag the slider, your code sets a new value for the slider, which then sets a new value for the slider, etc etc in a forever loop :-(

    One workaround is to neuter/silence the sliders/spinbox so that they only emit signals when a human clicks, not for C++ code. You can use the blockSignals(true) and blockSignals(false) for that, say like this:

    ...
    void ValueSetter::setValue(int value)
    {
        qDebug() << ui->spinbox->maximum() << round2(round2(value)/round2(Dpi));
     
        ui->spinbox->blockSignals(true);
        ui->spinbox->setValue(round2(round2(value)/round2(Dpi)));
        ui->spinbox->blockSignals(false);
    
        ui->slider->blockSignals(true);
        ui->slider->setValue(value);
        ui->slider->blockSignals(false);
    
        emit valueChanged(value);
    }
    ...

Log in to reply