비행기 스팟터(QML)
Plane Spotter
예제는 위치 및 포지셔닝 데이터 유형을 QML에 긴밀하게 통합하는 방법을 보여줍니다.
Plane Spotter
예제는 위치 및 위치 관련 C++ 데이터 유형을 QML에 통합하는 방법과 그 반대의 방법을 보여줍니다. 이는 네이티브 환경에서 CPU 집약적인 위치 계산을 실행하는 것이 바람직하지만 결과는 QML을 사용하여 표시해야 할 때 유용합니다.
이 예는 유럽 지도와 유럽을 가로지르는 두 노선의 비행기를 보여줍니다. 첫 번째 비행기는 오슬로와 베를린 사이를, 두 번째 비행기는 런던과 베를린 사이를 출퇴근합니다. 각 비행기의 위치 추적은 C++로 구현됩니다. 오슬로-베를린 비행기는 QML로 조종하고 런던-베를린 비행기는 C++ 파일럿이 조종합니다.
예제 실행하기
에서 예제를 실행하려면 Qt Creator에서 Welcome 모드를 열고 Examples 에서 예제를 선택합니다. 자세한 내용은 예제 빌드 및 실행을 참조하세요.
개요
이 예제에서는 위치 컨트롤러 구현의 일부로 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 과 매우 유사합니다. 이 예제는 PlaneController의 자체 파일럿 기능을 사용하는 C++ 코드와 CoordinateAnimation 을 파일럿으로 사용하는 QML 코드에서 PlaneController
의 위치 속성을 수정하는 방법을 보여줍니다. 오슬로-베를린 비행기는 QML 코드를 사용하여 애니메이션을 적용하고, 런던-베를린 비행기는 C++ 코드를 사용하여 애니메이션을 적용합니다.
어떤 파일럿을 사용하든 파일럿의 동작에 대한 결과는 C++와 QML에서 볼 수 있으므로 이 예제에서는 C++/QML 경계를 통해 위치 데이터를 방해받지 않고 직접 교환할 수 있음을 보여줍니다.
각 Plane
의 시각적 표현은 임의의 QtQuick 항목을 맵에 삽입할 수 있는 MapQuickItem 유형을 사용하여 이루어집니다:
// Plane.qml MapQuickItem { id: plane property string pilotName; property int bearing: 0; anchorPoint.x: image.width/2 anchorPoint.y: image.height/2 sourceItem: Item { //... } }
C++ 파일럿
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() } }
© 2025 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.