Plane Spotter (QML)
L'exemple « Plane Spotter » illustre l'intégration étroite des types de données de localisation et de positionnement dans QML.

L'exemple « Plane Spotter » montre comment intégrer des types de données C++ liés à la localisation et au positionnement dans QML, et inversement. Cela s'avère utile lorsqu'il est préférable d'effectuer des calculs de position gourmands en ressources CPU dans des environnements natifs, mais que les résultats doivent être affichés à l'aide de QML.
L'exemple présente une carte de l'Europe et des avions suivant deux itinéraires à travers le continent. Le premier avion effectue la liaison entre Oslo et Berlin, tandis que le second relie Londres à Berlin. Le suivi de la position de chaque avion est implémenté en C++. L'avion Oslo-Berlin est piloté en QML, tandis que celui de Londres-Berlin est commandé par un pilote en C++.
Exécution de l’exemple
Vous pouvez exécuter l’exemple à partir de :
- Qt Creator
Ouvrez le mode « Welcome » et sélectionnez l’exemple dans « Examples ». Pour plus d’informations, consultez Qt Creator: Tutoriel : Compiler et exécuter.
- Qt Extension for Visual Studio Code
Exécutez la commande « Qt: Open Qt examples » à partir de Command Palette, puis sélectionnez l’exemple dans la liste. Pour plus d’informations, consultez Qt Extension for Visual Studio Code: Tutoriel : Compiler et exécuter.
Présentation
Cet exemple utilise la fonctionnalité ` Q_GADGET ` dans le cadre de la mise en œuvre de son contrôleur de position. Elle permet l’intégration directe dans QML de types de valeurs C++ non basés surQObject.
L’objectif principal de la classe « PlaneController » est de suivre les coordonnées actuelles de l’avion à un instant donné. Elle expose la position via sa propriété « position ».
class PlaneController: public QObject
{
Q_OBJECT
Q_PROPERTY(QGeoCoordinate position READ position WRITE setPosition NOTIFY positionChanged)
// ...
};La fonction ` main() ` de l’exemple est chargée de lier les instances de la classe ` PlaneController ` au contexte QML :
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
PlaneController oslo2berlin;
PlaneController berlin2london;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("oslo2Berlin", &oslo2berlin);
engine.rootContext()->setContextProperty("berlin2London", &berlin2london);
engine.load(QUrl(QStringLiteral("qrc:/planespotter.qml")));
return app.exec();
}À l’instar des classes dérivées de ` QObject `, ` QGeoCoordinate ` peut être intégrée sans wrapper QML supplémentaire.
Pilotage des avions
Comme mentionné ci-dessus, l’objectif principal de la classe ` PlaneController ` est de suivre les positions actuelles des deux avions (Oslo-Berlin et Londres-Berlin) et de les communiquer sous forme de propriété à la couche QML. Son objectif secondaire est de définir et de faire progresser un avion le long d’une trajectoire de vol donnée. D’une certaine manière, elle peut agir comme un pilote. Cela ressemble beaucoup à l’ CoordinateAnimation, qui permet d’animer la transition d’une coordonnée géographique à une autre. Cet exemple montre comment la propriété de position de l’ PlaneController est modifiée par du code C++ utilisant les capacités de pilotage propres à l’ , et par du code QML utilisant l’ CoordinateAnimation comme pilote. L'avion Oslo-Berlin est animé à l'aide de code QML et l'avion Londres-Berlin à l'aide de code C++.
Quel que soit le pilote utilisé, les résultats de ses actions sont visibles en C++ et en QML ; cet exemple illustre ainsi un échange direct et sans entrave de données de position à travers la frontière C++/QML.
La représentation visuelle de chaque « Plane » est réalisée à l’aide du type « MapQuickItem », qui permet d’intégrer des éléments « QtQuick » arbitraires dans une carte :
// Plane.qml
MapQuickItem {
id: plane
property string pilotName;
property int bearing: 0;
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
sourceItem: Item {
//...
}
}Le pilote C++
L’avion C++ est piloté par du code C++. Les propriétés ` from ` et ` to ` de la classe `Controller` définissent l’origine et la destination que le pilote utilise pour calculer le cap de l’avion :
Q_PROPERTY(QGeoCoordinate from READ from WRITE setFrom NOTIFY fromChanged)
Q_PROPERTY(QGeoCoordinate to READ to WRITE setTo NOTIFY toChanged)Le pilote utilise les propriétés « QBasicTimer » et « QTimerEvents » pour mettre à jour en permanence la position. À chaque itération du minuteur, la méthode « PlaneController::updatePosition() » est appelée et une nouvelle position est calculée.
void updatePosition()
{
// simple progress animation
qreal progress;
QTime current = QTime::currentTime();
if (current >= finishTime) {
progress = 1.0;
timer.stop();
} else {
progress = ((qreal)startTime.msecsTo(current) / ANIMATION_DURATION);
}
setPosition(coordinateInterpolation(
fromCoordinate, toCoordinate, easingCurve.valueForProgress(progress)));
if (!timer.isActive())
emit arrived();
}Une fois la nouvelle position calculée, la méthode setPosition() est appelée et la notification de modification de la propriété transmet la nouvelle position à la couche QML.
L'avion C++ est lancé en cliquant sur l'avion :
Plane {
id: cppPlane
pilotName: "C++"
coordinate: berlin2London.position
TapHandler {
onTapped: {
if (cppPlaneAnimation.running || berlin2London.isFlying()) {
console.log("Plane still in the air.");
return;
}
berlin2London.swapDestinations();
cppPlaneAnimation.rotationDirection = berlin2London.position.azimuthTo(berlin2London.to)
cppPlaneAnimation.start();
cppPlane.departed();
}
}
}azimuthTo() calcule le relèvement en degrés d’une coordonnée à une autre. Notez que le code ci-dessus utilise une animation QML pour lier la rotation et le changement de position en un seul flux d’animation :
SequentialAnimation {
id: cppPlaneAnimation
property real rotationDirection : 0;
NumberAnimation {
target: cppPlane; property: "bearing"; duration: 1000
easing.type: Easing.InOutQuad
to: cppPlaneAnimation.rotationDirection
}
ScriptAction { script: berlin2London.startFlight() }
}Tout d’abord, la fonction ` NumberAnimation ` fait pivoter l’avion dans la bonne direction, puis la fonction ` startFlight() ` se charge de déclencher le changement de position de l’avion.
public slots:
void startFlight()
{
if (timer.isActive())
return;
startTime = QTime::currentTime();
finishTime = startTime.addMSecs(ANIMATION_DURATION);
timer.start(15, this);
emit departed();
}Le pilote QML
Le type CoordinateAnimation est utilisé pour contrôler le vol entre Oslo et Berlin, et inversement. Il remplace la fonction ScriptAction ci-dessus.
CoordinateAnimation {
id: coordinateAnimation; duration: 5000
target: oslo2Berlin; property: "position"
easing.type: Easing.InOutQuad
}L’ TapHandler de l’avion QML implémente la logique de définition de la trajectoire et lance l’animation lorsque cela est nécessaire.
TapHandler {
onTapped: {
if (qmlPlaneAnimation.running) {
console.log("Plane still in the air.");
return;
}
if (oslo2Berlin.position === berlin) {
coordinateAnimation.from = berlin;
coordinateAnimation.to = oslo;
} else if (oslo2Berlin.position === oslo) {
coordinateAnimation.from = oslo;
coordinateAnimation.to = berlin;
}
qmlPlaneAnimation.rotationDirection = oslo2Berlin.position.azimuthTo(coordinateAnimation.to)
qmlPlaneAnimation.start()
}
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.