Moduł Qt SDK — najważniejsze wskazówki

Kontynuując tworzenie aplikacji, należy zapoznać się z kilkoma szczegółami, dzięki którym aplikacje będą działały lepiej i wystąpi mniej problemów. W tym temacie omówiono ważne szczegóły, o których należy pamiętać.

Widok mapy

Pakiet ArcGIS Runtime SDK for Qt udostępnia trzy wzorce wyświetlania map w widoku mapy. W aplikacji AppStudio aplikacje pisane są w języku QML, dlatego używany jest typ mapy MapView.

Interfejs API QML firmy Qt Company umożliwia tworzenie aplikacji przeznaczonych na wiele platform w języku QML. Język QML oferuje deklaratywną, bardzo czytelną składnię umożliwiającą projektowanie i tworzenie elastycznych i płynnych interfejsów użytkownika dla aplikacji klasycznych i mobilnych. Środowisko ArcGIS Runtime SDK for Qt rozszerza język QML o typy, które pozwalają korzystać z funkcji środowiska ArcGIS Runtime. Obiekty są deklarowane hierarchicznie i mają możliwe do powiązania właściwości, które automatycznie zapewniają dynamiczne zachowanie. Do obsługi kodu proceduralnego można w razie potrzeby używać funkcji języka JavaScript. Ta możliwość jest bardzo istotna dla deweloperów, którzy mają doświadczenie w programowaniu aplikacji internetowych i chcą tworzyć aplikacje natywne.

Zadeklaruj obiekt Rectangle zawierający obiekt MapView. W obiekcie MapView zadeklaruj obiekt Map do wyświetlania i początkowy obiekt 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
        }
    }

Silnie typowane zmienne

Przy deklarowaniu właściwości w języku QML wygodnie i łatwo jest używać ogólnego typu zmiennej, var, jednak zawsze lepiej jest użyć silnie typowanych zmiennych. Silnie typowane zmienne jednoznacznie określają, jaki typ danych może być przechowywany w zmiennej, na przykład wartość typu liczba całkowita (integer), ciągi znakowy (string) lub dziesiętna (decimal). Silnie typowane zmienne mogą zapobiec przypisaniu błędnych wartości, są łatwiejsze przy czytaniu i debugowaniu w porównaniu z wartościami typu var. Zmienna typu var nie zapobiegnie przypisaniu do niej wartości typu dziesiętna (decimal), nawet jeśli zakładano, że wartość ma przechowywać tylko typ liczba całkowita (integer).

W poniższym przykładzie zmienna typu integer intValue ma najpierw przypisaną wartość 10. Później w kodzie ta sama zmienna zostaje zaktualizowana wartością typu ciąg znakowy (string).

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

Po uruchomieniu tego kodu na konsoli zostanie wyświetlony błąd odnoszący się jednoznacznie do numeru wiersza, w którym ustawiono wartość typu ciąg znakowy (string), z informacją Error: Cannot assign QString to int (Błąd: nie można przypisać typu QString do typu int), co ułatwia rozwiązywanie problemów z kodem.

Gdyby wartość nieprawidłowego typu zostanie przypisana do zmiennej typu var, błąd nie zostałby zgłoszony.

Skalowalne interfejsy użytkownika

Podczas projektowania interfejsu użytkownika aplikacji, ważne jest, aby wziąć pod uwagę stale rozwijający się zakres rozmiarów i rozdzielczości ekranu, na którym aplikacja może być używana. Można to osiągnąć poprzez dołączenie ikon, przycisków i tła dla każdej rozdzielczości wyświetlacza lub poprzez zastosowanie skalowalnej grafiki wektorowej (SVG).

W przypadku dołączania zestawu obrazów w różnych rozdzielczościach należy wybrać konwencję nazewnictwa plików, która wyraźnie rozróżnia rozmiary obrazów. Na przykład: image-name1x.png, image-name1.5x.png, image-name2x.png reprezentują obrazy o rozdzielczości 1-krotności DPI podstawowego, 1,5-krotności DPI podstawowego i 3-krotności DPI podstawowego.

Pliki SVG są idealne w przypadku niewielkich obrazów, zwykle ikon. Wyświetlanie dużych plików SVG może być powolne, dlatego należy wziąć pod uwagę użycie obrazu jako tła.

Więcej informacji na ten temat zawiera dokument Skalowalne interfejsy użytkownika środowiska Qt.

Debugowanie aplikacji

Aplikacja AppStudio jest zbudowana w oparciu o platformę Qt Framework, co oznacza możliwość korzystania ze wszystkich narzędzi debugowania używanych w środowisku Qt. Poniżej przedstawiono kilka przydatnych wskazówek i podpowiedzi dotyczących debugowania aplikacji Qt.

Użycie proxy internetowego

Podczas debugowania aplikacji AppStudio bardzo przydatne jest często narzędzie do debugowania aplikacji internetowych, które umożliwia przechwytywanie i analizowanie wysyłanych żądań oraz zwracanych odpowiedzi HTTP. Dwoma przykładami narzędzi do debugowania aplikacji internetowych, które umożliwiają wykonywanie tego zadania, są Fiddler i Charles. Aby skorzystać z tych narzędzi do debugowania aplikacji, wystarczy dodać do aplikacji: następujący kod w języku C++ QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, "127.0.0.1", 8888));. Ten kod może być ustawiany w czasie wykonywania i można go umieścić w pliku main.cpp lub dowolnej innej klasie C++. Oprócz użycia proxy na potrzeby debugowania, za pomocą QNetworkProxy::setApplicationProxy() można również określić serwer proxy instytucji. W tym celu należy określić adres URL i port serwera proxy instytucji. Więcej informacji na ten temat można znaleźć w dokumentacji klasy NetworkProxy modułu AppFramework.

Użycie metody JSON.stringify()

Jeśli używana jest metoda JSON.stringify(), należy unikać przekazywania samej referencji do obiektu. Należy użyć właściwości json obiektu jako argumentu, na przykład: JSON.stringify(graphic.geometry.json).

Model pamięci interfejsu QML API

Model pamięci używany na potrzeby aplikacji QML jest oparty na zbieraniu elementów zaśmiecających i czyszczeniu pamięci. Zmienne bez żadnych referencji zostaną wyczyszczone przez moduł zbierania elementów zaśmiecających i czyszczenia pamięci mechanizmu QML. Dlatego muszą istnieć jawne referencje do wszystkich obiektów, aby uniknąć zbierania elementów zaśmiecających i czyszczenia pamięci, gdy są one nadal używane.

Tworzenie obiektów za pomocą kodu JavaScript

Metoda ArccGISRuntimeEnvironment.createObject() tworzy i zwraca nową instancję obiektu za pośrednictwem silnika QML. Czas życia tych instancji jest określany przez ich obiekty nadrzędne. Gdy procedura czyszczenia pamięci usunie obiekt nadrzędny, powoduje to usunięcie jego instancji potomnych. Istnieją różne sposoby utrwalania instancji utworzonych za pomocą metody ArccGISRuntimeEnvironment.createObject(), w tym poniższe.

  • Obiekt nadrzędny można określić w trzecim, opcjonalnym parametrze metody ArccGISRuntimeEnvironment.createObject().
  • W deklaratywnym kodzie QML należy zadeklarować obiekt jako właściwość innego obiektu. Następnie w kodzie JavaScript należy utworzyć instancję obiektu za pomocą metody ArccGISRuntimeEnvironment.createObject(). Klasa zawierająca tę właściwość staje się obiektem nadrzędnym dla nowej instancji. Należy pamiętać, aby zadeklarować tę właściwość z użyciem tego samego typu QML środowiska ArcGIS Runtime podczas tworzenia instancji.

Jeśli nie określi się obiektu nadrzędnego, jako obiekt nadrzędny instancji obiektu zostaje ustawione środowisko JavaScript. Komponent QML śledzi instancję i usuwa ją w momencie, gdy nie ma więcej referencji JavaScript do instancji (czyli gdy instancja będzie poza zasięgiem).

Niektóre typy QML środowiska ArcGIS Runtime udostępniają metodę clone() służącą do tworzenia instancji obiektu danego typu. Utworzenie instancji za pomocą metody clone() powoduje, że jej obiektem nadrzędnym staje się środowisko JavaScript. Obiekt nadrzędny można zmienić przy użyciu właściwości parent.

Praca z modelami

Modele uzyskują jawny dostęp do instancji obiektów. Podczas pracy z modelami konieczne jest udostępnienie trwałych danych, aby uzyskać dostęp do modelu. Umieszczanie nowo utworzonych instancji obiektów bezpośrednio w obiekcie QML ListModel nie jest wystarczające do zapewnienia obsługi tych instancji przez cały czas ich życia, ponieważ w ten sposób nie są liczone referencje do tych instancji. (Zapoznaj się z poprzednią sekcją dotyczącą tworzenia obiektów z użyciem języka JavaScript). Jednym ze sposobów uniknięcia czyszczenia pamięci jest utworzenie właściwości będącej listą i dodawanie instancji do utrwalonej listy. Czas życia właściwości listy jest taki jak jej obiektu nadrzędnego.

// 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);

Ta koncepcja ma również zastosowanie do instancji obiektów listy opartych na klasie QQmlListProperty. Mimo że można taką listę przypisać bezpośrednio jako dane wejściowe modelu, należy tego unikać. Model utworzy niejawne referencje do elementów listy i elementy te zostaną usunięte podczas czyszczenia pamięci. Aby uzyskać poprawne wyniki, należy najpierw przypisać wszystkie elementy listy do listy lokalnej. Te jawne referencje będą trwałe i nie zostaną objęte wczesną procedurą zbierania elementów zaśmiecających i czyszczenia pamięci. W poniższym przykładzie budowany jest komponent list i wstawiane są wszystkie pola z tabeli obiektów. Następnie lista jest ustawiana jako model obiektu 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;
}

Unikalność obiektów

Nie ma żadnej gwarancji, że zostanie zwrócony ten sam obiekt, nawet w przypadku wywołania tej samej procedury pobierającej lub tej samej funkcji. Z tego względu należy unikać bezpośredniego porównywania obiektów, na przykład:

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)

Właściwości niestandardowe typów QML

Właściwość niestandardowa (zdefiniowana przez użytkownika) to właściwość, która jest dodawana do instancji o jednym z typów QML podczas jej deklarowania. Właściwość ta nie jest częścią typu, ale istnieje jako właściwość niestandardowa w konkretnej instancji. Język QML umożliwia dodawanie właściwości niestandardowych do instancji podczas ich deklarowania. Mimo że możliwe jest dodawanie właściwości niestandardowych do instancji o typie QML środowiska ArcGIS Runtime, właściwości takie mogą nie być zachowywane we wszystkich przypadkach ze względu na sposób obsługi instancji w interfejsie API. Z tego względu należy unikać używania właściwości niestandardowych w przypadku instancji o typach, które ich nie obsługują.

Właściwości niestandardowe są obsługiwane w przypadku poniższych typów QML i ich typów pochodnych. Inne typy QML środowiska ArcGIS Runtime ich nie obsługują.

  • ArcGISMapServiceInfo
  • Mapa bazowa
  • Poświadczenie
  • FeatureTable
  • Geobaza
  • GraphicsOverlay
  • LayerContent
  • Mapa
  • Portal
  • PortalTask
  • VectorTileSourceInfo

Praca z JSON

Wiele typów QML dziedziczy z interfejsu JsonSerializable, co umożliwia serializację danego typu oraz zapełnianie jego zawartości z użyciem formatu JSON. Podczas tworzenia obiektu na podstawie kodu JSON najpierw należy utworzyć instancję, a następnie przekazać tę instancję jako dane wejściowe metody.

Poniższy kod w języku JavaScript tworzy oraz zapełnia obiekt PictureMarkerSymbol na podstawie kodu JSON i używa go w nowej grafice.

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

Praca z przetłumaczonymi ciągami znakowymi

W przypadku wszystkich ciągów znakowych wyświetlanych w interfejsie użytkownika aplikacji należy użyć formatowania qsTr(), aby mieć pewność, że jest możliwa globalizacja tej aplikacji.

Przy definiowaniu logiki aplikacji ważne jest również wzięcie pod uwagę przetłumaczonych ciągów znakowych. Jeśli użytkownik będzie wybierać opcję na podstawie ciągów znakowych w interfejsie użytkownika, na przykład wybór z menu rozwijanego, każda instrukcja case w instrukcji switch musi używać przetłumaczonego ciągu znakowego.

W poniższym przykładzie panel informacji o aplikacji zostanie wyświetlony po wybraniu pozycji menu Informacje, niezależnie od tego, w jakim języku jest wyświetlana aplikacja:

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

Wyświetlanie z użyciem silnika OpenGL lub ANGLE w systemie Windows

Środowisko Qt dysponuje dwoma różnymi silnikami wyświetlania dla platformy Windows: OpenGL i DirectX za pośrednictwem ANGLE. Domyślnie środowisko Qt podejmuje próbę wyświetlania z użyciem silnika OpenGL. Jeśli odpowiednie sterowniki są niedostępne, do wyświetlania zostaje użyty silnik ANGLE. Poprzednie wersje środowiska ArcGIS Runtime obsługiwały tylko silnik ANGLE. Począwszy od środowiska ArcGIS Runtime w wersji 100.3.0, aplikacje mogą w pełni obsługiwać silniki OpenGL oraz ANGLE. Można dzięki temu korzystać z dowolnego z nich oraz z mechanizmu przejścia środowiska Qt na silnik rezerwowy, gdy silnik OpenGL nie jest dostępny w danym systemie. Więcej informacji na ten temat zawiera dokumentacja środowiska Qt.

Aby wybrać wyświetlanie z użyciem silnika OpenGL lub ANGLE jako domyślne, należy ustawić opcję Ustawienia > Platformy > Windows > Silnik renderowania grafiki w aplikacji AppStudio. Nie są potrzebne żadne zmiany kodu.