2

I have a code with a QDoubleSpinBox

ui->doubleSpinBoxExposure->setMinimum(0.001);
ui->doubleSpinBoxExposure->setMaximum(1000);
ui->doubleSpinBoxExposure->setSingleStep(1.0);

connect(ui->doubleSpinBoxExposure, SIGNAL(valueChanged(double)),
        this, SLOT(OndoubleSpinBoxExposure_valueChanged(double)));

void WidgetCameraParameter::OndoubleSpinBoxExposure_valueChanged(double value)
{
    if (!camera)
        return;
    if (camera->isOpen())
    {        
        float exposure = static_cast<float>(value);
        float cameraExposure;
        camera->setExposure(exposure);
        LOG_INFO() <<" setting exposure to " << value << " ms";
        cameraExposure = camera->exposure();
        LOG_INFO() <<" resulting exposure is " << cameraExposure << " ms";
    }
}

The problem is, when I step up in the gui or down, this happens twice. The starting parameter is value = 2. StepUp calls this function with 3, and directly afterwards with 4. And I have no idea why.

The stack trace is not helpfull:

1 WidgetCameraParameter::OndoubleSpinBoxExposure_valueChanged widgetcameraparameter.cpp 311 0x406c17
2 WidgetCameraParameter::qt_static_metacall moc_widgetcameraparameter.cpp 110 0x40811f
3 QMetaObject::activate qobject.cpp 3771 0x12bc2e1
4 QMetaObject::activate qobject.cpp 3633 0x12bc575
5 QDoubleSpinBox::valueChanged moc_qspinbox.cpp 436 0x15e66190 6 QDoubleSpinBoxPrivate::emitSignals qspinbox.cpp 1112 0x15e663b2 7 QAbstractSpinBoxPrivate::setValue qabstractspinbox.cpp 1741 0x15e6174d 8 QAbstractSpinBox::stepBy qabstractspinbox.cpp 643 0x15e62aba 9 QAbstractSpinBox::timerEvent qabstractspinbox.cpp 1246 0x15e5ffea 10 QObject::event qobject.cpp 1232 0x12bc918
11 QWidget::event qwidget.cpp 9347 0x15d0c544 12 QAbstractSpinBox::event qabstractspinbox.cpp 795 0x15e65930 13 QApplicationPrivate::notify_helper qapplication.cpp 3727 0x15cc85ca 14 QApplication::notify qapplication.cpp 3690 0x15cd1f4f 15 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1048 0x1295119
16 QCoreApplication::sendEvent qcoreapplication.h 234 0x12e4d87
17 QEventDispatcherWin32Private::sendTimerEvent qeventdispatcher_win.cpp 447 0x12e4d87
18 qt_internal_proc(HWND__ *, unsigned int, unsigned int, long) *16 qeventdispatcher_win.cpp 242 0x12e53d5
19 gapfnScSendMessage 0x771162fa 20 ?? 0x5c0f30
21 USER32!GetThreadDesktop 0x77116d3a 22 QEventDispatcherWin32Private::sendTimerEvent qeventdispatcher_win.cpp 456 0x12e4dc9
23 ?? 0x5c0f30
24 USER32!CharPrevW 0x771177c4 25 USER32!DispatchMessageW 0x7711788a 26 QEventDispatcherWin32::processEvents qeventdispatcher_win.cpp 629 0x12e4ae8
27 QWindowsGuiEventDispatcher::processEvents qwindowsguieventdispatcher.cpp 74 0x2496dab7 28 QEventLoop::processEvents qeventloop.cpp 136 0x12937c8
29 QEventLoop::exec qeventloop.cpp 214 0x1293c20
30 QCoreApplication::exec qcoreapplication.cpp 1336 0x129c30e
31 QGuiApplication::exec qguiapplication.cpp 1761 0x8461552
32 QApplication::exec qapplication.cpp 2901 0x15cc84a9 33 qMain main.cpp 28 0x40183d
34 WinMain *16 qtmain_win.cpp 104 0x4094c5
35 main 0x4179ad

Any idea how to debug this further?

EDIT: This only happens when I debug with breakpoints in the slot. Without the slot is only called once. The second call of the slot does not happen from any function within the slot function, but only after the slot has ended from the event loop.

You can loop at the complete code: https://github.com/pospiech/code/tree/master/libdev/devices/CameraViewer

Matthias Pospiech
  • 3,130
  • 18
  • 55
  • 76
  • 1
    maybe related : https://stackoverflow.com/questions/29985844/why-is-my-mousepressevent-called-twice – 463035818_is_not_an_ai Sep 12 '18 at 13:48
  • @user463035818 Further info: http://doc.qt.io/qt-5/designer-using-a-ui-file.html#automatic-connections – unlut Sep 12 '18 at 13:51
  • on the other hand, it seems like the naming convention for auto connection requires a `on_` prefix while you have a `On`... anyhow try to remove the `connect` to see what happens. If thats the "problem" the fix is trivial – 463035818_is_not_an_ai Sep 12 '18 at 13:54
  • https://bugreports.qt.io/browse/QTBUG-14259 ?? – paxdiablo Sep 12 '18 at 14:01
  • I've just tested this (without the camera stuff) and it works as expected, i.e. the slot is called only once per click, unless I press and hold. I am using Qt5.10.1. – scopchanov Sep 12 '18 at 14:12
  • If the connect is removed the slot is not called. – Matthias Pospiech Sep 12 '18 at 14:22
  • Maybe `camera->setExposure(exposure);` triggers the slot? – JLev Sep 12 '18 at 15:07
  • @JLev, that is easy to be tested. Let Matthias comment everything in the slot and put only one debug message. Basically my test was exactly the same. – scopchanov Sep 12 '18 at 15:49
  • I removed all code not needed for testing this issue. It can be tested without an actual camera (using a simulated one). It is reproducable. However - only with aktive debugging. If I run the same debug binary without debugging the problem does not occur. To me this looks like a Qt bug?! The camera interface does not trigger any slot. The spinbox is also not called after any command within the function, but only after the function is completed. The next trigger comes from the event loop not a function in my code. – Matthias Pospiech Sep 12 '18 at 17:13
  • I uploaded the code I am testing here to:https://github.com/pospiech/code/tree/master/libdev/devices/CameraViewer – Matthias Pospiech Sep 12 '18 at 17:23
  • Related to [pyQt: radioButton.isChecked() is executed twice](https://stackoverflow.com/questions/36808257/pyqt-radiobutton-ischecked-is-executed-twice) – Evandro Coan May 19 '20 at 20:25

2 Answers2

3

Looking at the QStyle::StyleHint enum, there is an interesting SH_SpinBox_ClickAutoRepeatThreshold constant. You can check its current value for your spin box, like this:

qDebug() << ui->doubleSpinBoxExposure->style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold);

This generally returns 500, which is the number of milliseconds after which the auto repeat gets triggered (i.e. if the user holds the mouse press on the up spin button for longer than that threshold, the spin box value will start increasing continuously).

To see if you have a timing issue, try changing that value, using a custom QStyle class like this:

#include <QProxyStyle>

class MyStyle : public QProxyStyle
{
public:
    int styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const
    {
        if(stylehint == QStyle::SH_SpinBox_ClickAutoRepeatThreshold)
        {
            return 2000; //2 seconds threshold
        }
        return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
    }
};

and setting an instance of it to the spin box style:

ui->doubleSpinBoxExposure->setStyle(new MyStyle());

Now it takes a lot (two long seconds) before the auto repeat gets triggered, and your issue should be gone, accordingly.

p-a-o-l-o
  • 9,807
  • 2
  • 22
  • 35
  • Indeed, this solves the problem. However the style is modified as well, which is not wanted. How can I keep the style? – Matthias Pospiech Sep 13 '18 at 07:31
  • Hi Matthias, I just provided some hints to debug the issue. If it happens at debug time only, and release builds are fine, just live with it (and don't bother editing the style the way I've shown). It happens because of debugging, which, generally speaking, slow down things, and can yield timing issues like yours. – p-a-o-l-o Sep 13 '18 at 07:49
  • Ok, that was also my approach, I just thought the style could be kept with simple adjustments in your code. – Matthias Pospiech Sep 13 '18 at 07:52
  • There was a mistake in my code, anyway (derive from QProxyStyle, not QCommonStyle). Edited. – p-a-o-l-o Sep 13 '18 at 07:59
0

It looks like you have a freezing gui-thread with your slot. You can try this code in your slot

void WidgetCameraParameter::OndoubleSpinBoxExposure_valueChanged(double value)
{
#define NUM_LOOPS 1000000000
    qDebug() << value;
    quint64 i = NUM_LOOPS;
    while(i--);
}

To avoid this, you have to move to another thread an operation that consumes a lot of CPU time.

In debug mode its because of autorepeating timer. Try this code to disable autorepeating in debug and, i think, you`ll understand:

*.h

...

#ifdef QT_DEBUG
    bool eventFilter(QObject *watched, QEvent *event) override;
#endif

...

*.c

...

    ui->setupUi(this);
#ifdef QT_DEBUG
    ui->doubleSpinBoxExposure->installEventFilter(this);
#endif

...

#ifdef QT_DEBUG
bool WidgetCameraParameter::eventFilter(QObject *watched, QEvent *event)
{
    QDoubleSpinBox *castSBox = static_cast<QDoubleSpinBox*>(watched);
    if(castSBox && event->type()==QEvent::Timer)
    {
        QTimerEvent *tEvent = static_cast<QTimerEvent*>(event);
        if(tEvent)
            qDebug() << "<--QEvent::Timer-->" << tEvent->timerId();
        return true;
    }
    return QObject::eventFilter(watched,event);
}
#endif
FrozenM
  • 115
  • 1
  • 3