QScrollBar: emit valueChanged once even if a slot takes too much time

Put also processing of control activation into initial timer check for possibly
pending mouse release event.

[ChangeLog][QtWidgets][QScrollBar] Fixed a bug where the valueChanged() signal
was emitted twice if a connected slot took too much time.

Task-number: QTBUG-42871
Change-Id: I7bad5279ef84463a033b55256d241d4445374081
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Pavel Krebs 2014-12-05 15:39:48 +01:00 committed by Giuseppe D'Angelo
parent b6514cf307
commit 1c1cce67fa
2 changed files with 44 additions and 3 deletions

View File

@ -593,13 +593,14 @@ void QScrollBar::mousePressEvent(QMouseEvent *e)
d->clickOffset = sliderLength / 2;
}
const int initialDelay = 500; // default threshold
d->activateControl(d->pressedControl, initialDelay);
QElapsedTimer time;
time.start();
d->activateControl(d->pressedControl, initialDelay);
repaint(style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this));
if (time.elapsed() >= initialDelay && d->repeatActionTimer.isActive()) {
// It took more than 500ms (the initial timer delay) to process the repaint(), we
// therefore need to restart the timer in case we have a pending mouse release event;
// It took more than 500ms (the initial timer delay) to process
// the control activation and repaint(), we therefore need
// to restart the timer in case we have a pending mouse release event;
// otherwise we'll get a timer event right before the release event,
// causing the repeat action to be invoked twice on a single mouse click.
// 50ms is the default repeat time (see activateControl/setRepeatAction).

View File

@ -58,6 +58,7 @@ private slots:
#ifndef QT_NO_WHEELEVENT
void QTBUG_27308();
#endif
void QTBUG_42871();
};
class SingleStepTestScrollBar : public QScrollBar {
@ -169,5 +170,44 @@ void tst_QScrollBar::QTBUG_27308()
}
#endif
class QTBUG_42871_Handler : public QObject {
Q_OBJECT
public:
int updatesCount;
QTBUG_42871_Handler() : QObject(), updatesCount(0) {}
public slots:
void valueUpdated(int) { ++updatesCount; QTest::qSleep(600); }
};
void tst_QScrollBar::QTBUG_42871()
{
QTBUG_42871_Handler myHandler;
QScrollBar scrollBarWidget(Qt::Vertical);
bool connection = connect(&scrollBarWidget, SIGNAL(valueChanged(int)), &myHandler, SLOT(valueUpdated(int)));
QVERIFY(connection);
scrollBarWidget.resize(100, scrollBarWidget.height());
centerOnScreen(&scrollBarWidget);
scrollBarWidget.show();
QTest::qWaitForWindowExposed(&scrollBarWidget);
QSignalSpy spy(&scrollBarWidget, SIGNAL(actionTriggered(int)));
QVERIFY(spy.isValid());
QCOMPARE(myHandler.updatesCount, 0);
QCOMPARE(spy.count(), 0);
// Simulate a mouse click on the "scroll down button".
const QPoint pressPoint(scrollBarWidget.width() / 2, scrollBarWidget.height() - 10);
const QPoint globalPressPoint = scrollBarWidget.mapToGlobal(pressPoint);
QMouseEvent mousePressEvent(QEvent::MouseButtonPress, pressPoint, globalPressPoint,
Qt::LeftButton, Qt::LeftButton, 0);
QApplication::sendEvent(&scrollBarWidget, &mousePressEvent);
QTest::qWait(1);
QMouseEvent mouseReleaseEvent(QEvent::MouseButtonRelease, pressPoint, globalPressPoint,
Qt::LeftButton, Qt::LeftButton, 0);
QApplication::sendEvent(&scrollBarWidget, &mouseReleaseEvent);
// Check that the action was triggered once.
QCOMPARE(myHandler.updatesCount, 1);
QCOMPARE(spy.count(), 1);
}
QTEST_MAIN(tst_QScrollBar)
#include "tst_qscrollbar.moc"