SatelliteInfo (C++/QML)▲
Key Qt Positioning classes used in this example:
The example displays the signal strength of all satellites in view. Any satellite that is currently used to calculate the GPS fix is marked pink. The number at the bottom of each signal bar is the individual satellite identifier.
The application operates in three different modes:
Application mode |
Description |
---|---|
running |
The application continuously queries the system for satellite updates. When new data is available it will be displayed. |
stopped |
The application stops updating the satellite information. |
single |
The application makes a single update request with a timeout of 10s. The display remains empty until the request was answered by the system. |
If the platform does not provide satellite information, the application automatically switches into a demo mode, whereby it continuously switches between predefined sets of satellite data.
Running the Example▲
To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.
Satellite Info Model▲
The key part of this example is the SatelliteModel data model. It represents the information about the satellites. It uses the Q_PROPERTY and QML_ELEMENT macros, so that it can be available from QML.
class
SatelliteModel : public
QAbstractListModel, public
QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(bool
running READ running WRITE setRunning NOTIFY runningChanged)
Q_PROPERTY(bool
satelliteInfoAvailable READ canProvideSatelliteInfo NOTIFY canProvideSatelliteInfoChanged)
Q_PROPERTY(int
entryCount READ entryCount NOTIFY entryCountChanged)
Q_PROPERTY(bool
singleRequestMode READ isSingleRequest WRITE setSingleRequest NOTIFY singleRequestChanged)
Q_INTERFACES(QQmlParserStatus)
QML_ELEMENT
public
:
explicit
SatelliteModel(QObject *
parent =
0
);
enum
{
IdentifierRole =
Qt::
UserRole +
1
,
InUseRole,
SignalStrengthRole,
ElevationRole,
AzimuthRole
}
;
//From QAbstractListModel
int
rowCount(const
QModelIndex &
amp;parent) const
override
;
QVariant data(const
QModelIndex &
amp;index, int
role) const
override
;
QHash&
lt;int
, QByteArray&
gt; roleNames() const
override
;
//From QQmlParserStatus
void
classBegin() override
{}
void
componentComplete() override
;
signals
:
void
runningChanged();
void
entryCountChanged();
void
errorFound(int
code);
void
canProvideSatelliteInfoChanged();
void
singleRequestChanged();
public
slots:
void
clearModel();
void
updateDemoData();
}
;
The SatelliteModel object creates an instance of QGeoSatelliteInfoSource using the createDefaultSource() method. Once the source is created, the satellitesInViewUpdated() and satellitesInUseUpdated() signals are used to notify about the changes in satellite information.
SatelliteModel::
SatelliteModel(QObject *
parent) :
QAbstractListModel(parent), source(0
), m_componentCompleted(false
), m_running(false
),
m_runningRequested(false
), demo(false
), isSingle(false
), singleRequestServed(false
)
{
source =
QGeoSatelliteInfoSource::
createDefaultSource(this
);
if
(!
demo &
amp;&
amp; !
source) {
qWarning() &
lt;&
lt; "No satellite data source found. Changing to demo mode."
;
demo =
true
;
}
if
(!
demo) {
source-&
gt;setUpdateInterval(3000
);
connect(source, SIGNAL(satellitesInViewUpdated(QList&
lt;QGeoSatelliteInfo&
gt;)),
this
, SLOT(satellitesInViewUpdated(QList&
lt;QGeoSatelliteInfo&
gt;)));
connect(source, SIGNAL(satellitesInUseUpdated(QList&
lt;QGeoSatelliteInfo&
gt;)),
this
, SLOT(satellitesInUseUpdated(QList&
lt;QGeoSatelliteInfo&
gt;)));
connect(source, SIGNAL(errorOccurred(QGeoSatelliteInfoSource::
Error)),
this
, SLOT(error(QGeoSatelliteInfoSource::
Error)));
}
if
(demo) {
timer =
new
QTimer(this
);
connect(timer, SIGNAL(timeout()), this
, SLOT(updateDemoData()));
timer-&
gt;start(3000
);
}
}
The aforementioned signals provide the lists of QGeoSatelliteInfo objects that represent satellites in view and satellites in use, respectively. This data is used to update the model.
void
SatelliteModel::
satellitesInViewUpdated(const
QList&
lt;QGeoSatelliteInfo&
gt; &
amp;infos)
{
if
(!
running())
return
;
int
oldEntryCount =
knownSatellites.count();
QSet&
lt;int
&
gt; satelliteIdsInUpdate;
foreach (const
QGeoSatelliteInfo &
amp;info, infos)
satelliteIdsInUpdate.insert(info.satelliteIdentifier());
QSet&
lt;int
&
gt; toBeRemoved =
knownSatelliteIds -
satelliteIdsInUpdate;
//We reset the model as in reality just about all entry values change
//and there are generally a lot of inserts and removals each time
//Hence we don't bother with complex model update logic beyond resetModel()
beginResetModel();
knownSatellites =
infos;
//sort them for presentation purposes
std::
sort(knownSatellites.begin(), knownSatellites.end());
//remove old "InUse" data
//new satellites are by default not in "InUse"
//existing satellites keep their "inUse" state
satellitesInUse -=
toBeRemoved;
knownSatelliteIds =
satelliteIdsInUpdate;
endResetModel();
if
(oldEntryCount !=
knownSatellites.count())
emit entryCountChanged();
}
void
SatelliteModel::
satellitesInUseUpdated(const
QList&
lt;QGeoSatelliteInfo&
gt; &
amp;infos)
{
if
(!
running())
return
;
beginResetModel();
satellitesInUse.clear();
foreach (const
QGeoSatelliteInfo &
amp;info, infos)
satellitesInUse.insert(info.satelliteIdentifier());
endResetModel();
}
If the satellite info source is not available, demo data is used to simulate satellite information updates.
void
SatelliteModel::
updateDemoData()
{
static
bool
flag =
true
;
QList&
lt;QGeoSatelliteInfo&
gt; satellites;
if
(flag) {
for
(int
i =
0
; i&
lt;5
; i++
) {
QGeoSatelliteInfo info;
info.setSatelliteIdentifier(i);
info.setSignalStrength(20
+
20
*
i);
satellites.append(info);
}
}
else
{
for
(int
i =
0
; i&
lt;9
; i++
) {
QGeoSatelliteInfo info;
info.setSatelliteIdentifier(i*
2
);
info.setSignalStrength(20
+
10
*
i);
satellites.append(info);
}
}
satellitesInViewUpdated(satellites);
flag ? satellitesInUseUpdated(QList&
lt;QGeoSatelliteInfo&
gt;() &
lt;&
lt; satellites.at(2
))
:
satellitesInUseUpdated(QList&
lt;QGeoSatelliteInfo&
gt;() &
lt;&
lt; satellites.at(3
));
flag =
!
flag;
emit errorFound(flag);
if
(isSingleRequest() &
amp;&
amp; !
singleRequestServed) {
singleRequestServed =
true
;
setRunning(false
);
}
}
The model is later used in QML to visualize the data.
Exposing the Model to QML▲
To expose SatelliteModel to QML, we use the QML_ELEMENT macro. See the QQmlEngine class documentation for more details on it.
To make the type available in QML, we need to update our build accordingly.
CMake Build▲
For a CMake-based build, we need to add the following to the CMakeLists.txt:
qt_add_qml_module(satelliteinfo
URI Local
VERSION 1.0
QML_FILES satelliteinfo.qml
NO_RESOURCE_TARGET_PATH
)
qmake Build▲
For a qmake build, we need to modify the satelliteinfo.pro file in the following way:
CONFIG +=
qmltypes
QML_IMPORT_NAME =
Local
QML_IMPORT_MAJOR_VERSION =
1