Qt QML 모범 사례

앱 개발을 진행하는 과정에서는 앱의 성능을 개선하고 발생하는 문제를 줄일 수 있는 몇 가지 세부정보를 기억해 두어야 합니다. 이 항목에서는 명심해야 하는 중요한 세부정보에 대해 설명합니다.

맵 보기

ArcGIS Runtime SDK for Qt는 맵 뷰에 맵을 표시하기 위한 세 가지 패턴을 제공합니다. AppStudio에서는 QML에 앱을 작성하므로 MapView 맵 유형을 사용하게 됩니다.

The Qt Company의 QML API를 통해 QML을 사용하여 크로스 플랫폼 앱을 만들 수 있습니다. QML은 네이티브 데스크톱 및 모바일 애플리케이션을 위한 유연하고 즉각적인 UI를 설계 및 구축할 수 있는 판독성 높은 선언적 구문입니다. ArcGIS Runtime SDK for QtArcGIS Runtime 기능을 제공하는 QML 유형으로 QML을 확장합니다. 객체는 자동으로 동적 동작을 제공하도록 계층적으로 선언되며 바인딩 가능한 등록정보를 지닙니다. JavaScript 함수는 필요에 따라 절차 코드를 제공하는 데 사용됩니다. 이는 웹 개발이 이미 익숙하고 네이티브 앱을 개발하려는 개발자를 위한 중요한 기능입니다.

Rectangle를 포함하는 MapView을 선언합니다. MapView에서 Map을 선언하여 초기 Viewpoint를 표시합니다.

Rectangle {
    width: 800
    height: 600
     property real scaleFactor: System.displayScaleFactor
     // Map view UI presentation at top
    MapView {
        id: mv
         anchors.fill: parent
        wrapAroundMode: Enums.WrapAroundModeDisabled
         Map {
            BasemapTopographic {}
            initialViewpoint: viewPoint
             FeatureLayer {
                id: featureLayer
                 ServiceFeatureTable {
                    id: featureTable
                    url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"
                }
            }
        }
         ViewpointCenter {
            id: viewPoint
            center: Point {
                x: -13630484
                y: 4545415
                spatialReference: SpatialReference {
                    wkid: 102100
                }
            }
            targetScale: 300000
        }
    }

강력한 유형의 변수

QML에서 등록정보를 선언하는 경우 일반 변수 유형 var을 사용하면 쉽고 편리하지만 강력한 유형의 변수를 사용하는 것이 항상 더 좋은 옵션입니다. 강력한 유형의 변수는 변수에 저장할 수 있는 데이터 유형(예시: 정수, 문자열 또는 소수 값)을 명시적으로 나타냅니다. 강력한 유형의 변수는 잘못된 값이 할당되지 않도록 할 수 있고 읽기 쉬우며 var 유형의 비교 변수를 디버그하기도 더 쉽습니다. var 유형의 변수는 값에 정수만 와야 하는 경우에도 소수 값이 할당되는 것을 막지 않습니다.

다음 예시에서 정수 변수 intValue에는 본래 10의 값이 할당되었습니다. 나중에 코드에서 해당 변수가 문자열 값으로 업데이트됩니다.

property int intValue = 10
...
intValue = "A string value"

해당 코드를 실행하면 문자열 값이 설정된 라인 번호를 명시적으로 참조하고 오류: QString을 int에 할당할 수 없음을 나타내는 오류가 콘솔에 표시되어 코드 문제 해결이 더 쉬워집니다.

잘못된 유형의 값이 var 유형의 변수에 할당되면 오류가 보고되지 않습니다.

확장 가능한 UI

앱의 UI를 디자인하는 경우 앱이 사용될 수 있는 화면 크기 및 해상도의 범위가 계속해서 변화한다는 점을 고려하는 것이 중요합니다. 각 디스플레이 해상도에 대한 아이콘, 버튼, 배경을 포함하거나 SVG(Scalable Vector Graphics)를 사용하여 이를 실현할 수 있습니다.

다양한 해상도의 이미지 집합을 포함하는 경우 이미지 크기를 명확하게 구분하는 파일 명명 규칙을 선택합니다. 예를 들어 image-name1x.png, image-name1.5x.png, image-name2x.png는 기본 DPI의 1배, 기본 DPI의 1.5배, 기본 DPI의 3배인 이미지라는 것을 나타냅니다.

SVG 파일은 일반적으로 아이콘과 같은 작은 이미지에 적합합니다. 큰 SVG 파일은 렌더링 속도가 느릴 수 있으므로 배경에 이미지를 사용하는 것이 좋습니다.

자세한 내용은 Qt의 확장 가능한 UI를 참고하세요.

앱 디버깅

AppStudio는 Qt 프레임워크를 기반으로 구성되므로 Qt와 함께 사용되는 모든 동일한 디버깅 유틸리티에 접근할 수 있습니다. 아래는 Qt 앱 디버깅을 위한 몇 가지 유용한 팁과 요령입니다.

웹 프록시 사용

AppStudio 앱을 디버깅할 때에는 웹 디버깅 유틸리티를 활용하여 전송된 HTTP 요청과 반환된 응답을 캡처하고 분석하면 유용한 경우가 많습니다. Fiddler 및 Charles는 이러한 작업을 수행하는 데 사용되는 웹 디버깅 유틸리티의 두 가지 예시입니다. 이러한 도구를 사용하면 다음과 같은 C++ 코드를 앱에 추가하여 앱을 디버깅할 수 있습니다. QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, "127.0.0.1", 8888));. 이 코드는 런타임에 설정할 수 있으며 main.cpp 또는 다른 C++ 클래스에 위치할 수 있습니다. 디버깅을 위해 프록시를 사용하는 것 외에도 QNetworkProxy::setApplicationProxy()를 사용하여 기관의 프록시 서버를 지정할 수도 있습니다. 이렇게 하려면 기관 프록시 서버의 URL과 포트를 지정해야 합니다. 자세한 내용은 AppFramework NetworkProxy 문서에서 확인할 수 있습니다.

JSON.stringify() 사용

JSON.stringify() 메소드를 사용할 때 객체 참조 자체를 전달해서는 안 됩니다. 객체의 json 등록정보를 인수로 사용합니다(예시: JSON.stringify(graphic.geometry.json)).

QML API 메모리 모델

QML 앱에 사용되는 메모리 모델은 가비지 수집을 기반으로 합니다. 참조되지 않는 변수는 QML Engine 가비지 수집기로 정리됩니다. 따라서 아직 사용 중인 개체가 가비지 수집되지 않도록 하려면 모든 객체를 분명하게 참조해야 합니다.

JavaScript를 사용한 객체 생성

ArccGISRuntimeEnvironment.createObject() 메소드는 QML 엔진을 통해 객체의 새 인스턴스를 생성 및 반환합니다. 이러한 인스턴스의 수명은 인스턴스의 상위 객체에 의해 결정됩니다. 상위 객체가 가비지 수집되면 하위 인스턴스도 가비지 수집됩니다. 다음을 비롯한 다양한 방식을 통해 ArccGISRuntimeEnvironment.createObject()로 생성된 인스턴스를 지속할 수 있습니다.

  • ArccGISRuntimeEnvironment.createObject()의 세 번째 선택적 매개변수에 상위 객체를 지정할 수 있습니다.
  • QML 선언형 코드에서 객체를 또 다른 객체의 등록정보로 선언합니다. 그런 다음 JavaScript 코드에서 ArccGISRuntimeEnvironment.createObject()로 객체를 인스턴스화합니다. 등록정보를 포함하는 클래스가 새 인스턴스의 상위가 됩니다. 인스턴스화하는 동안에는 등록정보를 동일한 ArcGIS Runtime QML 유형으로 선언해야 합니다.

상위를 지정하지 않으면 JavaScript가 객체 인스턴스의 상위로 설정됩니다. QML은 인스턴스에 대한 남은 JavaScript 참조가 없을 경우 인스턴스를 추적하여 삭제합니다(즉, 인스턴스가 범위에서 벗어나는 경우).

일부 ArcGIS Runtime QML 유형은 해당 유형의 객체 인스턴스를 생성하는 데 사용되는 clone() 메소드를 포함합니다. clone()을 사용하여 새 인스턴스를 생성하면 JavaScript가 상위로 지정됩니다. parent 등록정보를 사용하여 상위를 변경할 수 있습니다.

모델 사용

모델은 객체 인스턴스에 명시적으로 접근합니다. 모델을 사용할 때는 모델이 접근할 수 있는 영구 데이터를 제공해야 합니다. 새로 생성된 객체 인스턴스를 QML ListModel에 직접적으로 삽입하는 것만으로 이러한 인스턴스의 수명을 유지할 수 없는 이유는 이렇게 할 경우 이러한 인스턴스의 참조가 계산되지 않기 때문입니다. (JavaScript를 사용한 객체 생성에 대한 이전 섹션을 참고하세요.) 가비지 수집을 피할 수 있는 한 방법은 목록 형식의 등록정보를 생성한 다음 인스턴스를 지속된 목록에 추가하는 것입니다. 목록 등록정보의 수명은 상위와 동일합니다.

// In a QML declaration:
ListModel {
  id: myListModel
  property var geoms: []
}

//...
// In a JavaScript function:
var newPoint = point.clone();

// avoid the following, because newPoint is not reference counted 
// myListModel.append(
//    {"geometry", newPoint
//    });  

// do this instead to give newPoint the same lifetime as myListModel
myListModel.geoms.push(newPoint);

이러한 개념은 QQmlListProperty 기반의 목록 객체 인스턴스에도 적용됩니다. 이러한 목록은 모델의 입력으로 바로 배정할 수 있지만 이렇게 하지 않는 것이 좋습니다. 모델은 목록 항목에 대한 비명시적 참조를 생성하므로 항목이 가비지 수집됩니다. 정확한 결과를 얻으려면 먼저 모든 목록 요소를 로컬 목록에 배정하세요. 이와 같은 분명한 참조는 영구 보존되므로 초기 가비지 수집을 방지할 수 있습니다. 다음 예에서는 list 컴포넌트를 만들고 피처 테이블의 모든 필드를 삽입합니다. 그러면 목록이 ComboBox의 모델로 설정됩니다.

GeodatabaseFeatureTable {
    id: featureTable
}

ComboBox {
    id: comboBox
//    model: featureTable.fields // avoid this, because the model will create non-explicit references
    textRole: "name"
}

property var fieldList: []

function initFieldListModel() {
    for (var i = 0; i < featureTable.fields.length; ++i) {
        fieldList.push(featureTable.fields[i]);
    }
    comboBox.model = fieldList;
}

객체 고유성

동일한 getter 또는 함수를 호출한다고 해서 같은 객체가 다시 반환된다는 보장은 없습니다. 따라서 객체의 직접 비교는 지양해야 합니다. 예시:

Map { id: map }
...
var viewpoint = map.initialViewpoint;
// Avoid comparisons like the following code.
// Although the objects' contents are identical, 
// the objects may be different objects.
if (viewpoint === map.initialViewpoint)

QML 유형의 사용자 설정 등록정보

사용자 설정 등록정보는 선언되는 QML 유형의 인스턴스에 추가됩니다. 등록정보는 유형의 일부가 아니지만 특정 인스턴스의 사용자 설정 등록정보로 존재합니다. QML 언어는 선언되는 사용자 설정 등록정보를 인스턴스에 추가할 수 있게 해줍니다. 사용자 설정 등록정보는 ArcGIS Runtime QML 유형 인스턴스에 추가할 수 있지만 경우에 따라서는 인스턴스가 API에서 유지되는 방식으로 인해 등록정보가 유지되지 않을 수도 있습니다. 따라서 지원되지 않는 유형의 인스턴스에서는 사용자 설정 등록정보를 사용하지 않는 것이 좋습니다.

다음 QML 유형, 그리고 이러한 유형에서 파생되는 유형은 사용자 설정 등록정보를 지원합니다. 다른 ArcGIS Runtime QML 유형은 사용자 설정 등록정보를 지원하지 않습니다.

  • ArcGISMapServiceInfo
  • 베이스맵
  • Credential
  • FeatureTable
  • 지오데이터베이스
  • GraphicsOverlay
  • LayerContent
  • 포털
  • PortalTask
  • VectorTileSourceInfo

JSON 사용

다수의 QML 유형은 JsonSerializable에서 상속되므로 유형을 직렬화하거나 콘텐츠를 JSON 형식으로 채울 수 있습니다. JSON에서 객체를 생성하는 경우에는 먼저 인스턴스를 생성한 다음 해당 인스턴스를 메소드에 대한 입력으로 전달합니다.

이 JavaScript 코드는 JSON의 PictureMarkerSymbol을 생성하고 채우며, 이를 새 그래픽에서 사용합니다.

Graphic {
  id: myGraphic


  property var pmsJson: {"type": "esriPMS", "url": "http://myurl.com/folder/my-icon.png","width": 60,"height": 60, "angle":20}


  Component.onCompleted: {
    var pmsFromJson = ArcGISRuntimeEnvironment.createObject("PictureMarkerSymbol", {json: pmsJson});
    pmsFromJson.errorChanged.connect(function(error){ verify(false, error.message + " (" + error.additionalMessage + ")"); });
    myGraphic.symbol = pmsFromJson;
  }
}

번역된 문자열 작업

앱의 UI에 표시되는 모든 문자열은 앱을 국제화할 수 있도록 qsTr() 형식을 사용해야 합니다.

앱 로직을 정의할 때 번역된 문자열을 고려하는 것 또한 중요합니다. 사용자가 UI의 문자열을 기반으로 옵션을 선택하는 경우(예시: 드롭다운 메뉴에서 선택) switch 문 내의 각 사례는 번역된 문자열을 사용해야 합니다.

다음 예시에서는 앱에서 표시하는 언어와 관계없이 정보 메뉴 항목을 선택하는 경우 정보 패널이 표시됩니다.

case qsTr("About"):
    pageView.hideSearchItem()
    panelDockItem.addDock("aboutPanel")
    break

WindowsOpenGL 또는 ANGLE 렌더링

Qt에는 Windows 플랫폼을 위한 두 가지 렌더링 엔진인 OpenGLANGLE을 통한 DirectX 이 있습니다. 기본 설정에 따라 Qt는 OpenGL을 사용하여 렌더링을 시도합니다. 하지만 올바른 드라이버가 없는 경우에는 ANGLE을 사용하여 렌더링을 수행합니다. ArcGIS Runtime의 이전 출시 버전에서는 ANGLE만 지원했습니다. ArcGIS Runtime 100.3.0부터는 앱에서 OpenGLANGLE을 모두 지원할 수 있습니다. 따라서 OpenGL을 특정 시스템에서 사용할 수 없는 경우 둘 중 원하는 렌더링 엔진과 Qt 대체 메커니즘을 사용할 수 있습니다. 자세한 내용은 Qt의 문서를 참고하세요.

기본값으로 OpenGLANGLE 렌더링 중에서 선택하려면 AppStudio에서 설정 > 플랫폼 > Windows > 그래픽 렌더링 엔진 옵션을 사용하세요. 코드 변경은 필요하지 않습니다.