飞机制志者(QML)
Plane Spotter
示例演示了将位置和定位数据类型紧密集成到 QML 的过程中。
Plane Spotter
示例演示了如何将位置和定位相关的 C++ 数据类型集成到 QML,反之亦然。当希望在本地环境中运行计算密集型的位置计算但在 QML 中显示结果时,这非常有用。
示例显示了一个欧洲的地图和两条横跨欧洲的航线上的飞机。第一架飞机在奥斯陆和柏林之间通勤,第二架飞机在伦敦和柏林之间通勤。每架飞机的位置跟踪是在 C++ 中实现的。奥斯陆-柏林飞机由 QML 控制,而伦敦-柏林飞机由 C++ 驾驶员控制。
运行示例
要从 Qt Creator 运行示例,打开 欢迎 模式并从 示例 中选择示例。更多信息,请访问 构建和运行示例。
概述
此示例使用 Q_GADGET 功能作为其位置控制器实现的一部分。它允许 直接集成 非 QObject 的 C++ 值类型到 QML 中。
PlaneController
类的主要目的是在给定时间跟踪飞机的当前位置。它通过其位置属性公开位置。
class PlaneController: public QObject { Q_OBJECT Q_PROPERTY(QGeoCoordinate position READ position WRITE setPosition NOTIFY positionChanged) // ... };
示例的 main()
函数负责将 PlaneController
类实例绑定到 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(); }
类似于 QObject 派生类,QGeoCoordinate 可以直接集成,无需额外的 QML 包装器。
控制飞机
如上所述,PlaneController
类的主要目的是跟踪两架飞机(奥斯陆-柏林和伦敦-柏林)的当前位置并将它们作为属性广告到 QML 层。其次的目的是设置和沿给定飞行路径推进飞机。在某种程度上,它可以充当飞行员。这与 CoordinateAnimation 非常相似,它可以逐个动画化从地理位置到另一个地理位置的过渡。此示例演示了如何使用 C++ 代码和 PlaneController 自身的驾驶能力及使用 CoordinateAnimation 作为驾驶员的 QML 代码修改 PlaneController
的位置属性。奥斯陆-柏林飞机使用 QML 代码进行动画,伦敦-柏林飞机使用 C++ 代码进行动画。
无论使用哪种驾驶员,驾驶员的操作结果在C++和QML中都可见,因此示例展示了在C++/QML边界之间无阻碍的直接位置数据交换。
使用MapQuickItem类型生成每个Plane
的视觉表示,这允许将任意QtQuick元素嵌入到地图中
// Plane.qml MapQuickItem { id: plane property string pilotName; property int bearing: 0; anchorPoint.x: image.width/2 anchorPoint.y: image.height/2 sourceItem: Item { //... } }
cpp驾驶员
C++飞机由C++控制。控制器类的from
和to
属性设置驾驶员使用的起点和终点,以计算飞机的方位角
Q_PROPERTY(QGeoCoordinate from READ from WRITE setFrom NOTIFY fromChanged) Q_PROPERTY(QGeoCoordinate to READ to WRITE setTo NOTIFY toChanged)
驾驶员使用QBasicTimer和QTimerEvents来不断更新位置。在每个计时器迭代过程中调用PlaneController::updatePosition()
并计算新的位置。
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(); }
计算了新的位置后,调用setPosition()
,然后属性随后的更改通知将新位置推送到QML层。
通过单击飞机启动C++飞机
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()计算从一个坐标到另一个坐标的角度。请注意,上述代码使用QML动画将旋转和位置更改结合成一个动画流程。
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() } }
首先,NumberAnimation将飞机旋转到正确的方向,完成后,startFlight()
函数负责开始飞机的位置改变。
public slots: void startFlight() { if (timer.isActive()) return; startTime = QTime::currentTime(); finishTime = startTime.addMSecs(ANIMATION_DURATION); timer.start(15, this); emit departed(); }
QML驾驶员
使用CoordinateAnimation类型来控制从奥斯陆到柏林的飞行以及相反方向的飞行。它替换了上面的ScriptAction。
CoordinateAnimation { id: coordinateAnimation; duration: 5000 target: oslo2Berlin; property: "position" easing.type: Easing.InOutQuad }
QML飞机的TapHandler实现了航线设置的逻辑,并在需要时启动动画。
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() } }
© 2024 Qt公司有限公司。此处包含的文档贡献是相应所有者的版权。此处提供的文档是根据免费软件基金会发布的GNU自由文档许可证版本1.3的条款许可的。Qt及其相关标志是芬兰和/或世界各地的Qt公司有限公司的商标。所有其他商标均为其相应所有者的财产。