Советы по работе с Qt QML

Если вы занимаетесь разработкой приложений, вам следует знать несколько моментов, которые улучшат работу ваших приложений, а также снизят риск возможных проблем. В этом разделе рассматриваются важные вещи, которые необходимо учитывать.

Вид карты

ArcGIS Runtime SDK for Qt предлагает три варианта отображения карты в виде карты. В AppStudio вы пишите приложение в QML, поэтому будете использовать тип карты MapView.

QML API от компании Qt предлагает написание кросс-платформенных приложений с помощью QML, декларативного, легко читаемого синтаксиса для проектирования и создания гибких пользовательских интерфейсов для собственных настольных и мобильных приложений. ArcGIS Runtime SDK for Qt расширяет QML типами QML, предоставляющими функциональность ArcGIS Runtime. Объекты декларируются иерархически и имеют привязываемые свойства для автоматического обеспечения динамического поведения. Функции 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"

При запуске кода, на консоли отображается ошибка, которая однозначно идентифицирует номер строки, где задано строковое значение, отображая Error: Cannot assign QString to int, что облегчает исправление кода.

Если значение неверного типа присвоено переменной типа var, сообщения об ошибке не будет.

Масштабируемые пользовательские интерфейсы

При разработке интерфейса приложения, важно учитывать все возможные размеры экранов и разрешения, с которыми приложение может использоваться. Это можно сделать, используя значки, кнопки и фон для каждого разрешения, или воспользоваться масштабируемой векторной графикой (SVG).

При включении наборов изображений с разными разрешениями, выбирайте имена файлов, позволяющие четко дифференцировать размеры изображений. Например: image-name1x.png, image-name1.5x.png, image-name2x.png представляют изображения с 1 базовым DPI, 1.5-кратным базовым DPI и 3-кратным базовым DPI.

Файлы SVG хорошо подходят для небольших изображений, обычно для значков. Большие файлы SVG могут отображаться медленно, поэтому желательно использовать фоновые изображения.

Более подробно см. в разделе Масштабируемые пользовательские интерфейсы Qt.

Отладка вашего приложения

AppStudio построен поверх Qt Framework, а это значит, что у вас есть доступ ко всем тем же утилитам отладки, которые используются в Qt. Ниже приведены несколько советов и подсказок по отладке приложений Qt.

Использование веб-прокси

При отладке приложений AppStudio обычно используется утилита отладки, получающая и анализирующая запросы HTTP, которые отправляются, и ответы, которые на них приходят. Fiddler и Charles - это два примера утилит веб-отладки, которые используются для выполнения этой задачи. Эти инструменты можно использовать для отладки приложения, добавляя следующий код C++ в ваше приложение: QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, "127.0.0.1", 8888));. Этот код может быть установлен во время выполнения и может находиться либо в вашем main.cpp, либо в каком-либо другом классе C ++. Помимо использования proxy для поиска ошибок, QNetworkProxy::setApplicationProxy() также можно использовать для настройки прокси-сервера вашей организации. Для этого укажите URL и порт прокси-сервера вашей организации. Подробную информацию можно найти в документации NetworkProxy AppFramework.

Использование 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(). Класс, содержащий свойство, становится родителем для нового экземпляра. Убедитесь, что вы декларируете свойство того же типа QML ArcGIS Runtime, экземпляр которого вы создали.

Если вы не указали родителя, JavaScript задается как родитель экземпляра объекта. QML отслеживает экземпляр и удаляет его, когда не остается ссылок JavaScript на экземпляр (то есть, когда экземпляр выходит за пределы области видимости).

Некоторые типы QML ArcGIS Runtime включают метод clone(), который используется для создания экземпляра объекта этого типа. При использовании clone() для создания экземпляра, его родителем будет JavaScript. Вы можете изменить родителя с помощью свойства parent.

Работа с моделями

Модели обращаются к экземплярам объектов в явном виде. При работе с моделями необходимо предоставить сохраненные данные для доступа к модели. Размещение вновь созданных экземпляров объектов непосредственно в ListModel QML недостаточно для поддержания жизненного цикла этих экземпляров, поскольку это не приводит к подсчету этих экземпляров. (Смотрите предыдущий раздел о создании объекта при помощи 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;
}

Уникальность объектов

Нет никакой гарантии, что вы получите один и тот же объект, даже если будете использовать одинаковые средства или функции. Поэтому следует избегать прямого сравнения объектов, например:

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 позволяет добавлять пользовательские свойства к экземплярам, когда вы их декларируете. Когда вы добавляете пользовательские свойства к экземплярам типов QML ArcGIS Runtime, это свойство может быть не сохранено в тех случаях, когда экземпляры поддерживаются в API. В связи с этим следует избегать пользовательских свойств для экземпляров типов, которые их не поддерживают.

Следующие типы QML и типы, полученные на их основе, поддерживают пользовательские свойства. Другие типы QML ArcGIS Runtime этого не делают.

  • ArcGISMapServiceInfo
  • Базовая карта
  • Учетные данные
  • FeatureTable
  • База геоданных
  • GraphicsOverlay
  • LayerContent
  • Карта
  • Портал
  • PortalTask
  • VectorTileSourceInfo

Работа с JSON

Многие типы QML унаследованы от JsonSerializable, это дает возможность сериализировать этот тип или заполнить его содержимое в JSON. При создании объекта из JSON сначала создайте экземпляр, затем передайте этот экземпляр как вход для данного метода.

Этот код JavaScript создает и заполняет PictureMarkerSymbol из JSON и использует его в новой графике.

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;
  }
}

Работа с переведенными строками

Все строки, которые отображаются в интерфейсе приложения, должны использовать форматирование qsTr() для обеспечения возможности глобализации приложения.

Также важно учитывать перевод строк при разработке логики приложения. Если пользователь выберет опцию, основанную на строках интерфейса, например, выбор параметра из ниспадающего списка, каждый пункт в выражении переключения должен использовать переведенную строку.

В следующем примере при выборе элемента меню О программе отображается панель информации, независимо от языка, на котором отображается приложение.

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

OpenGL или ANGLE отображение в Windows

У Qt есть два разных механизма отрисовки для платформы Windows: OpenGL и DirectX через ANGLE. По умолчанию Qt попытается выполнить отрисовку с помощью OpenGL. Если необходимые драйверы недоступны, то он вернется к использованию ANGLE для отображения. Предыдущие версии ArcGIS Runtime поддерживали только ANGLE. Начиная с ArcGIS Runtime 100.3.0, приложения могут полностью поддерживать и OpenGL, и ANGLE, так что можно использовать либо механизм отрисовки, либо резервный механизм Qt, когда OpenGL не может использоваться в данной системе. Более подробно см. документацию Qt.

Для выбора между отображением по умолчанию OpenGL ANGLE, используйте опции Настройки > Платформы > Windows > Механизм отображения графики в AppStudio. Изменения кода не нужны.