mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
Avoid accidental child widget value changes when scrolling scroll areas
This adds a new QgsScrollArea widget which is a subclass of QScrollArea. QgsScrollArea has extra logic which temporarily blocks wheel events from hitting child widgets for a short period following a scroll of the area. This means that when scrolling a scroll area using the mouse wheel, values won't be accidentally changed if the mouse cursor momentarily lands on top of a widget. QScrollArea should no longer be used in any QGIS code or plugins, instead use QgsScrollArea to benefit from this fix.
This commit is contained in:
parent
f60dc81102
commit
907ad02af8
2
src/gui/CMakeLists.txt
Normal file → Executable file
2
src/gui/CMakeLists.txt
Normal file → Executable file
@ -296,6 +296,7 @@ SET(QGIS_GUI_SRCS
|
||||
qgsscalerangewidget.cpp
|
||||
qgsscalevisibilitydialog.cpp
|
||||
qgsscalewidget.cpp
|
||||
qgsscrollarea.cpp
|
||||
qgssearchquerybuilder.cpp
|
||||
qgsshortcutsmanager.cpp
|
||||
qgsslider.cpp
|
||||
@ -442,6 +443,7 @@ SET(QGIS_GUI_MOC_HDRS
|
||||
qgsscalerangewidget.h
|
||||
qgsscalevisibilitydialog.h
|
||||
qgsscalewidget.h
|
||||
qgsscrollarea.h
|
||||
qgssearchquerybuilder.h
|
||||
qgsshortcutsmanager.h
|
||||
qgsslider.h
|
||||
|
127
src/gui/qgsscrollarea.cpp
Normal file
127
src/gui/qgsscrollarea.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/***************************************************************************
|
||||
qgsscrollarea.cpp
|
||||
-----------------
|
||||
begin : March 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include "qgsscrollarea.h"
|
||||
|
||||
// milliseconds to swallow child wheel events for after a scroll occurs
|
||||
#define TIMEOUT 1000
|
||||
|
||||
QgsScrollArea::QgsScrollArea( QWidget *parent )
|
||||
: QScrollArea( parent )
|
||||
, mFilter( new ScrollAreaFilter( this, viewport() ) )
|
||||
{
|
||||
viewport()->installEventFilter( mFilter );
|
||||
}
|
||||
|
||||
void QgsScrollArea::wheelEvent( QWheelEvent *e )
|
||||
{
|
||||
//scroll occurred, reset timer
|
||||
scrollOccurred();
|
||||
QScrollArea::wheelEvent( e );
|
||||
}
|
||||
|
||||
void QgsScrollArea::scrollOccurred()
|
||||
{
|
||||
mTimer.setSingleShot( true );
|
||||
mTimer.start( TIMEOUT );
|
||||
}
|
||||
|
||||
bool QgsScrollArea::hasScrolled() const
|
||||
{
|
||||
return mTimer.isActive();
|
||||
}
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
ScrollAreaFilter::ScrollAreaFilter( QgsScrollArea *parent, QWidget *viewPort )
|
||||
: QObject( parent )
|
||||
, mScrollAreaWidget( parent )
|
||||
, mViewPort( viewPort )
|
||||
{}
|
||||
|
||||
bool ScrollAreaFilter::eventFilter( QObject *obj, QEvent *event )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::ChildAdded:
|
||||
{
|
||||
// need to install filter on all child widgets as well
|
||||
QChildEvent *ce = static_cast<QChildEvent *>( event );
|
||||
addChild( ce->child() );
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::ChildRemoved:
|
||||
{
|
||||
QChildEvent *ce = static_cast<QChildEvent *>( event );
|
||||
removeChild( ce->child() );
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
if ( obj == mViewPort )
|
||||
{
|
||||
// scrolling scroll area - kick off the timer to block wheel events in children
|
||||
mScrollAreaWidget->scrollOccurred();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mScrollAreaWidget->hasScrolled() )
|
||||
{
|
||||
// swallow wheel events for children shortly after scroll occurs
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QObject::eventFilter( obj, event );
|
||||
}
|
||||
|
||||
void ScrollAreaFilter::addChild( QObject *child )
|
||||
{
|
||||
if ( child && child->isWidgetType() )
|
||||
{
|
||||
child->installEventFilter( this );
|
||||
|
||||
// also install filter on existing children
|
||||
Q_FOREACH ( QObject *c, child->children() )
|
||||
{
|
||||
addChild( c );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollAreaFilter::removeChild( QObject *child )
|
||||
{
|
||||
if ( child && child->isWidgetType() )
|
||||
{
|
||||
child->removeEventFilter( this );
|
||||
|
||||
// also remove filter on existing children
|
||||
Q_FOREACH ( QObject *c, child->children() )
|
||||
{
|
||||
removeChild( c );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///@endcond PRIVATE
|
100
src/gui/qgsscrollarea.h
Normal file
100
src/gui/qgsscrollarea.h
Normal file
@ -0,0 +1,100 @@
|
||||
/***************************************************************************
|
||||
qgsscrollarea.h
|
||||
---------------
|
||||
begin : March 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSSCROLLAREA_H
|
||||
#define QGSSCROLLAREA_H
|
||||
|
||||
#include <QScrollArea>
|
||||
#include "qgis_gui.h"
|
||||
#include <QTimer>
|
||||
class ScrollAreaFilter;
|
||||
|
||||
/**
|
||||
* \class QgsScrollArea
|
||||
* \ingroup gui
|
||||
* A QScrollArea subclass with improved scrolling behavior.
|
||||
*
|
||||
* QgsScrollArea should be used instead of QScrollArea widgets.
|
||||
* In most cases the use is identical, however QgsScrollArea
|
||||
* has extra logic to avoid wheel events changing child widget
|
||||
* values when the mouse cursor is temporarily located over
|
||||
* a child widget during a scroll event.
|
||||
*
|
||||
* All QGIS code and plugins should use QgsScrollArea in place
|
||||
* of QScrollArea.
|
||||
*
|
||||
* \note added in QGIS 3.0
|
||||
*/
|
||||
class GUI_EXPORT QgsScrollArea : public QScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsScrollArea.
|
||||
*/
|
||||
explicit QgsScrollArea( QWidget *parent = nullptr );
|
||||
|
||||
/**
|
||||
* Should be called when a scroll occurs on with the
|
||||
* QScrollArea itself or its child viewport().
|
||||
*/
|
||||
void scrollOccurred();
|
||||
|
||||
/**
|
||||
* Returns true if a scroll recently occurred within
|
||||
* the QScrollArea or its child viewport()
|
||||
*/
|
||||
bool hasScrolled() const;
|
||||
|
||||
protected:
|
||||
void wheelEvent( QWheelEvent *event ) override;
|
||||
|
||||
private:
|
||||
QTimer mTimer;
|
||||
ScrollAreaFilter *mFilter = nullptr;
|
||||
};
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* \class ScrollAreaFilter
|
||||
* Swallows wheel events for QScrollArea children for a short period
|
||||
* following a scroll.
|
||||
*/
|
||||
class ScrollAreaFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
ScrollAreaFilter( QgsScrollArea *parent = nullptr,
|
||||
QWidget *viewPort = nullptr );
|
||||
|
||||
protected:
|
||||
bool eventFilter( QObject *obj, QEvent *event ) override;
|
||||
|
||||
private:
|
||||
QgsScrollArea *mScrollAreaWidget = nullptr;
|
||||
QWidget *mViewPort = nullptr;
|
||||
|
||||
void addChild( QObject *child );
|
||||
void removeChild( QObject *child );
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSSCROLLAREA_H
|
86
src/ui/qgsoptionsbase.ui
Normal file → Executable file
86
src/ui/qgsoptionsbase.ui
Normal file → Executable file
@ -311,7 +311,7 @@
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="mOptionsStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>13</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="mOptionsPageGeneral">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
@ -328,7 +328,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_01">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_01">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -340,8 +340,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>857</width>
|
||||
<height>680</height>
|
||||
<width>856</width>
|
||||
<height>679</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_28">
|
||||
@ -1014,7 +1014,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_03">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_03">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -1026,8 +1026,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>541</width>
|
||||
<height>1065</height>
|
||||
<width>839</width>
|
||||
<height>1009</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_22">
|
||||
@ -1544,7 +1544,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_11">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_11">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -1556,8 +1556,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>495</width>
|
||||
<height>685</height>
|
||||
<width>856</width>
|
||||
<height>679</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_27">
|
||||
@ -1912,7 +1912,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_04">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_04">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -1924,8 +1924,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>674</width>
|
||||
<height>936</height>
|
||||
<width>839</width>
|
||||
<height>827</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_22">
|
||||
@ -2663,7 +2663,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<widget class="QgsScrollArea" name="scrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -2675,8 +2675,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>142</width>
|
||||
<height>239</height>
|
||||
<width>112</width>
|
||||
<height>219</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_46">
|
||||
@ -2814,7 +2814,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_06">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_06">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -2826,8 +2826,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>501</width>
|
||||
<height>316</height>
|
||||
<width>453</width>
|
||||
<height>281</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_25">
|
||||
@ -3157,7 +3157,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_05">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_05">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -3169,8 +3169,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>604</width>
|
||||
<height>589</height>
|
||||
<width>506</width>
|
||||
<height>533</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_30">
|
||||
@ -3601,7 +3601,7 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_12">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_12">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -3613,8 +3613,8 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>571</height>
|
||||
<width>393</width>
|
||||
<height>530</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_39">
|
||||
@ -3870,7 +3870,7 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_07">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_07">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -3882,8 +3882,8 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>543</width>
|
||||
<height>696</height>
|
||||
<width>488</width>
|
||||
<height>612</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||
@ -4448,7 +4448,7 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_02">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_02">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -4460,8 +4460,8 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>412</width>
|
||||
<height>368</height>
|
||||
<width>345</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
@ -4587,7 +4587,7 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_08">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_08">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -4599,8 +4599,8 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>408</width>
|
||||
<height>531</height>
|
||||
<width>332</width>
|
||||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_15">
|
||||
@ -4800,7 +4800,7 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_09">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_09">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -4812,8 +4812,8 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>273</width>
|
||||
<height>236</height>
|
||||
<width>221</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_32">
|
||||
@ -4909,7 +4909,7 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="mOptionsScrollArea_10">
|
||||
<widget class="QgsScrollArea" name="mOptionsScrollArea_10">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@ -4921,8 +4921,8 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>843</width>
|
||||
<height>689</height>
|
||||
<width>856</width>
|
||||
<height>679</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
@ -5435,6 +5435,12 @@ The bigger the number, the faster zooming with the mouse wheel will be.</string>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsScrollArea</class>
|
||||
<extends>QScrollArea</extends>
|
||||
<header>qgsscrollarea.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsPasswordLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
|
Loading…
x
Reference in New Issue
Block a user