Skip to content

Commit 5654886

Browse files
committed
New class QgsFocusWatcher for easier handling of focus events
Usually QObjects must subclass and override methods like focusOutEvent to handle focus events. Using this class as an event filter avoids the need to subclass objects and the focus events can be directly caught using the emitted signals.
1 parent 6173539 commit 5654886

File tree

7 files changed

+240
-0
lines changed

7 files changed

+240
-0
lines changed

python/gui/gui.sip

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
%Include qgsfiledropedit.sip
7878
%Include qgsfilewidget.sip
7979
%Include qgsfilterlineedit.sip
80+
%Include qgsfocuswatcher.sip
8081
%Include qgsformannotationitem.sip
8182
%Include qgsgenericprojectionselector.sip
8283
%Include qgsgeometryrubberband.sip

python/gui/qgsfocuswatcher.sip

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/** \ingroup gui
2+
* \class QgsFocusWatcher
3+
* A event filter for watching for focus events on a parent object. Usually QObjects must
4+
* subclass and override methods like focusOutEvent to handle focus events. Using this class
5+
* as an event filter avoids the need to subclass objects and the focus events can be directly
6+
* caught using the emitted signals.
7+
* \note added in 2.16
8+
*/
9+
10+
class QgsFocusWatcher: QObject
11+
{
12+
%TypeHeaderCode
13+
#include <qgsfocuswatcher.h>
14+
%End
15+
16+
public:
17+
18+
/** Constructor for QgsFocusWatcher.
19+
* @param parent parent widget to catch focus events for. This class will automatically be
20+
* installed as an event filter for parent.
21+
*/
22+
explicit QgsFocusWatcher( QObject* parent /TransferThis/ );
23+
24+
virtual bool eventFilter( QObject* obj, QEvent* event );
25+
26+
signals:
27+
28+
/** Emitted when parent object's focus changes.
29+
* @param focused true if object gained focus, false if object lost focus
30+
*/
31+
void focusChanged( bool focused );
32+
33+
//! Emitted when parent object gains focus.
34+
void focusIn();
35+
36+
//! Emitted when parent object loses focus.
37+
void focusOut();
38+
};

src/gui/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ SET(QGIS_GUI_SRCS
206206
qgsfiledropedit.cpp
207207
qgsfilewidget.cpp
208208
qgsfilterlineedit.cpp
209+
qgsfocuswatcher.cpp
209210
qgsformannotationitem.cpp
210211
qgsgenericprojectionselector.cpp
211212
qgsgeometryrubberband.cpp
@@ -350,6 +351,7 @@ SET(QGIS_GUI_MOC_HDRS
350351
qgsfiledropedit.h
351352
qgsfilewidget.h
352353
qgsfilterlineedit.h
354+
qgsfocuswatcher.h
353355
qgsformannotationitem.h
354356
qgsgenericprojectionselector.h
355357
qgsgroupwmsdatadialog.h

src/gui/qgsfocuswatcher.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/***************************************************************************
2+
qgsfocuswatcher.h
3+
-----------------
4+
Date : April 2016
5+
Copyright : (C) 2016 by Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsfocuswatcher.h"
17+
#include <QEvent>
18+
19+
QgsFocusWatcher::QgsFocusWatcher( QObject* parent )
20+
: QObject( parent )
21+
{
22+
Q_ASSERT( parent );
23+
parent->installEventFilter( this );
24+
}
25+
26+
bool QgsFocusWatcher::eventFilter( QObject*, QEvent* event )
27+
{
28+
switch ( event->type() )
29+
{
30+
case QEvent::FocusIn:
31+
emit focusChanged( true );
32+
emit focusIn();
33+
break;
34+
case QEvent::FocusOut:
35+
emit focusChanged( false );
36+
emit focusOut();
37+
break;
38+
default:
39+
break;
40+
}
41+
return false;
42+
}

src/gui/qgsfocuswatcher.h

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/***************************************************************************
2+
qgsfocuswatcher.h
3+
-----------------
4+
Date : April 2016
5+
Copyright : (C) 2016 by Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSFOCUSWATCHER_H
17+
#define QGSFOCUSWATCHER_H
18+
19+
#include <QObject>
20+
21+
/** \ingroup gui
22+
* \class QgsFocusWatcher
23+
* A event filter for watching for focus events on a parent object. Usually QObjects must
24+
* subclass and override methods like focusOutEvent to handle focus events. Using this class
25+
* as an event filter avoids the need to subclass objects and the focus events can be directly
26+
* caught using the emitted signals.
27+
* \note added in 2.16
28+
*/
29+
30+
class GUI_EXPORT QgsFocusWatcher : public QObject
31+
{
32+
Q_OBJECT
33+
34+
public:
35+
36+
/** Constructor for QgsFocusWatcher.
37+
* @param parent parent widget to catch focus events for. This class will automatically be
38+
* installed as an event filter for parent.
39+
*/
40+
explicit QgsFocusWatcher( QObject* parent );
41+
42+
virtual bool eventFilter( QObject* obj, QEvent* event ) override;
43+
44+
signals:
45+
46+
/** Emitted when parent object's focus changes.
47+
* @param focused true if object gained focus, false if object lost focus
48+
*/
49+
void focusChanged( bool focused );
50+
51+
//! Emitted when parent object gains focus.
52+
void focusIn();
53+
54+
//! Emitted when parent object loses focus.
55+
void focusOut();
56+
57+
};
58+
59+
#endif //QGSFOCUSWATCHER_H

tests/src/gui/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ ADD_QGIS_TEST(doublespinbox testqgsdoublespinbox.cpp)
130130
ADD_QGIS_TEST(dualviewtest testqgsdualview.cpp)
131131
ADD_QGIS_TEST(fieldexpressionwidget testqgsfieldexpressionwidget.cpp)
132132
ADD_QGIS_TEST(filewidget testqgsfilewidget.cpp)
133+
ADD_QGIS_TEST(focuswatcher testqgsfocuswatcher.cpp)
133134
ADD_QGIS_TEST(mapcanvastest testqgsmapcanvas.cpp)
134135
ADD_QGIS_TEST(projectionissues testprojectionissues.cpp)
135136
ADD_QGIS_TEST(qgsguitest testqgsgui.cpp)

tests/src/gui/testqgsfocuswatcher.cpp

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/***************************************************************************
2+
testqgsfocuswatcher.cpp
3+
----------------------
4+
Date : April 2016
5+
Copyright : (C) 2016 Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
17+
#include <QtTest/QtTest>
18+
19+
#include "qgsfocuswatcher.h"
20+
#include <QApplication>
21+
#include <QLineEdit>
22+
23+
class TestQgsFocusWatcher: public QObject
24+
{
25+
Q_OBJECT
26+
private slots:
27+
void initTestCase(); // will be called before the first testfunction is executed.
28+
void cleanupTestCase(); // will be called after the last testfunction was executed.
29+
void init(); // will be called before each testfunction is executed.
30+
void cleanup(); // will be called after every testfunction.
31+
32+
void testSignals();
33+
34+
private:
35+
36+
};
37+
38+
void TestQgsFocusWatcher::initTestCase()
39+
{
40+
}
41+
42+
void TestQgsFocusWatcher::cleanupTestCase()
43+
{
44+
}
45+
46+
void TestQgsFocusWatcher::init()
47+
{
48+
}
49+
50+
void TestQgsFocusWatcher::cleanup()
51+
{
52+
}
53+
54+
void TestQgsFocusWatcher::testSignals()
55+
{
56+
QWidget* w = new QWidget();
57+
QLineEdit* e1 = new QLineEdit( w );
58+
QLineEdit* e2 = new QLineEdit( w );
59+
QApplication::setActiveWindow( w ); //required for focus events
60+
e1->setFocus();
61+
62+
QgsFocusWatcher* watcher1 = new QgsFocusWatcher( e1 );
63+
QgsFocusWatcher* watcher2 = new QgsFocusWatcher( e2 );
64+
65+
QSignalSpy spyFocusIn1( watcher1, SIGNAL( focusIn() ) );
66+
QSignalSpy spyFocusOut1( watcher1, SIGNAL( focusOut() ) );
67+
QSignalSpy spyFocusChanged1( watcher1, SIGNAL( focusChanged( bool ) ) );
68+
QSignalSpy spyFocusIn2( watcher2, SIGNAL( focusIn() ) );
69+
QSignalSpy spyFocusOut2( watcher2, SIGNAL( focusOut() ) );
70+
QSignalSpy spyFocusChanged2( watcher2, SIGNAL( focusChanged( bool ) ) );
71+
72+
e2->setFocus();
73+
QCOMPARE( spyFocusIn1.count(), 0 );
74+
QCOMPARE( spyFocusOut1.count(), 1 );
75+
QCOMPARE( spyFocusChanged1.count(), 1 );
76+
QCOMPARE( spyFocusChanged1.last().at( 0 ).toBool(), false );
77+
QCOMPARE( spyFocusIn2.count(), 1 );
78+
QCOMPARE( spyFocusOut2.count(), 0 );
79+
QCOMPARE( spyFocusChanged2.count(), 1 );
80+
QCOMPARE( spyFocusChanged2.last().at( 0 ).toBool(), true );
81+
82+
e1->setFocus();
83+
QCOMPARE( spyFocusIn1.count(), 1 );
84+
QCOMPARE( spyFocusOut1.count(), 1 );
85+
QCOMPARE( spyFocusChanged1.count(), 2 );
86+
QCOMPARE( spyFocusChanged1.last().at( 0 ).toBool(), true );
87+
QCOMPARE( spyFocusIn2.count(), 1 );
88+
QCOMPARE( spyFocusOut2.count(), 1 );
89+
QCOMPARE( spyFocusChanged2.count(), 2 );
90+
QCOMPARE( spyFocusChanged2.last().at( 0 ).toBool(), false );
91+
92+
delete w;
93+
}
94+
95+
96+
QTEST_MAIN( TestQgsFocusWatcher )
97+
#include "testqgsfocuswatcher.moc"

0 commit comments

Comments
 (0)