Prassi consigliate di Qt QML

Se si desidera proseguire a sviluppare app, è opportuno essere a conoscenza di alcuni dettagli che possono migliorare le performance delle app con minori problemi. In questa sezione sono inoltre riportati importanti informazioni da tenere presenti.

Vista mappa

ArcGIS Runtime SDK for Qt offre tre modelli di visualizzazione delle mappe in una vista mappa. Su AppStudio, l'applicazione verrà scritta in QML, pertanto verrà utilizzato il tipo di mappa MapView.

L'API QML di The Qt Company consente di creare app multipiattaforma con QML, una sintassi dichiarativa e altamente leggibile per la progettazione e la creazione di interfacce utente reattive e fluide per applicazioni native desktop e mobili. ArcGIS Runtime SDK for Qt espande QML con tipi QML che forniscono funzionalità ArcGIS Runtime. Gli oggetti vengono dichiarati gerarchicamente e hanno proprietà collegabili per fornire automaticamente un comportamento dinamico. Le funzioni di JavaScript vengono utilizzate per fornire un codice procedurale se necessario. Si tratta di una feature importante per sviluppatori che hanno già familiarità con lo sviluppo Web e che desiderano sviluppare app native.

Dichiarare un Rectangle contenente MapView. In MapView, dichiarare un Map da visualizzare e un Viewpoint iniziale.

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

Variabili fortemente tipizzate

Quando si dichiarano le proprietà in QML, utilizzare il tipo di variabile var è facile e conveniente; tuttavia, è sempre meglio usare variabili fortemente tipizzate. Le variabili fortemente tipizzate dichiarano esplicitamente il tipo di dati che possono essere memorizzati nella variabile, ad esempio, un intero, una stringa o un valore decimale. Le variabili fortemente tipizzate possono prevenire l'assegnazione dei valori errati, sono più semplici da leggere e permettono una facile esecuzione del debug rispetto alle variabili di tipo var. Le variabili di tipo var non impediscono a un valore decimale di essere assegnato a esse, anche se il valore deve solamente contenere interi.

Nel seguente esempio, alla variabile intera intValue viene inizialmente assegnato un valore di 10. Più avanti nel codice, la stessa variabile viene aggiornata con un valore stringa.

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

Quando questo codice viene eseguito, viene visualizzato un errore nella console che fa riferimento esplicitamente al numero della riga dove è stato impostato il valore stringa, dichiarando Errore: impossibile assegnare QString a int, rendendo più facile la risoluzione dei problemi nel codice.

Se viene assegnato un valore con il tipo sbagliato a una variabile di tipo var, l'errore non viene riportato.

Interfacce utente scalabili

Durante la progettazione dell'interfaccia utente dell'app, è importante considerare la gamma in costante evoluzione di dimensioni dello schermo e risoluzioni in cui l'app può essere utilizzata. Ciò può essere ottenuto includendo icone, pulsanti e sfondi per ogni risoluzione di visualizzazione, oppure utilizzando grafiche vettoriali scalabili (SVG).

Al momento dell'inclusione di un set di immagini con risoluzioni diverse, scegliere una convenzione di denominazione dei file che differenzia chiaramente le dimensioni delle immagini. Ad esempio: nome-immagine1x.png, nome-immagine1.5x.png, nome-immagine2x.png rappresentano immagini di 1 volta il DPI di base, 1.5 volte il DPI di base e 2 volte il DPI di base.

I file SVG sono ideali per le piccole immagini, solitamente le icone. I grandi file SVG possono essere lenti da renderizzare, quindi considerare di utilizzare le immagini per gli sfondi.

Per ulteriori informazioni, consultare Interfacce utente scalabili di Qt.

Debug dell'app

AppStudio viene creato a partire dal framework Qt, il che significa che si ottiene l'accesso a tutti i servizi di debug usati con Qt. Di seguito sono presentati alcuni consigli utili per il debug delle app Qt.

Utilizzando un proxy Web

Quando si esegue il debug delle app AppStudio, risulta spesso utile un servizio di debug Web per acquisire e analizzare le richieste HTTP inviate e le risposte restituite. Fiddler e Charles sono due esempi di servizi di debug Web adoperati per eseguire tale operazione. È possibile utilizzare questi strumenti per eseguire il debug di un'app aggiungendo il seguente codice C++ nell'app: QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, "127.0.0.1", 8888));. Questo codice può essere impostato in fase di runtime e può trovarsi o in main.cpp o in qualche altra classe C++. Oltre a utilizzare un proxy per il debug, è anche possibile usare QNetworkProxy::setApplicationProxy() per specificare il server proxy dell'organizzazione. A tal fine, specificare l'URL e la porta del server proxy dell'organizzazione. È possibile trovare ulteriori informazioni nella documentazione di QNetworkProxy di AppFramework.

Usare JSON.stringify()

Quando si utilizza il metodo JSON.stringify(), non passare il riferimento oggetto. Come argomento, usare la proprietà json dell'oggetto, per esempio: JSON.stringify(graphic.geometry.json).

Modello di memoria API QML

Il modello di memoria API impiegato per le app QML si basa sulla raccolta di rifiuti. Le variabili non riferite saranno pulite dal collettore di rifiuti di QML Engine. Pertanto, tutti gli oggetti devono essere riferiti esplicitamente per evitare che siano eliminati mentre sono ancora in uso.

Creazione di oggetti con JavaScript

Il metodo ArccGISRuntimeEnvironment.createObject() crea e restituisce nuove istanze di un oggetto tramite il motore QML. La durata di queste istanze viene stabilita dall'oggetto padre dell'istanza. Se l'oggetto padre viene ripulito, lo saranno anche le sue istanze figlie. Esistono vari modi per rendere permanente un'istanza creata con ArccGISRuntimeEnvironment.createObject(), inclusi i seguenti.

  • È possibile specificare l'oggetto padre nel terzo parametro opzionale di ArccGISRuntimeEnvironment.createObject().
  • Nel codice dichiarativo QML, dichiarare l'oggetto come proprietà di un altro oggetto. Quindi, nel codice JavaScript, creare un'istanza dell'oggetto con ArccGISRuntimeEnvironment.createObject(). La classe contenente la proprietà diventa l'oggetto padre della nuova istanza. Accertarsi di dichiarare che la proprietà è dello stesso tipo QML ArcGIS Runtime dell'istanza che si sta creando.

Se non si specifica un oggetto padre, JavaScript viene impostato come padre dell'istanza dell'oggetto. QML traccia l'istanza e la elimina quando non ci sono riferimenti JavaScript all'istanza rimanenti (ovvero quando l'istanza fuoriesce dalla portata).

Alcuni tipi QML ArcGIS Runtime includono un metodo clone() utilizzato per creare una nuova istanza oggetto di quel tipo. Se si utilizza clone() per creare un'istanza, JavaScript sarà il suo oggetto padre. È possibile modificare l'oggetto padre utilizzando la proprietà parent.

Lavorare con i modelli

I modelli accedono esplicitamente alle istanze dell'oggetto. Quando si lavora con i modelli, occorre fornire dati persistenti per consentire al modello di accedervi. Collocare le istanze oggetto di nuova creazione direttamente in un ListModel QML non è sufficiente per mantenere la durata di tali istanze, perché in questa maniera le suddette istanze non vengono conteggiate come riferimenti. (Consultare la sezione precedente su come creare un oggetto con JavaScript) Un modo per evitare l'eliminazione è creare una proprietà che sia un elenco e aggiungere le istanze all'elenco reso permanente. La durata della proprietà elenco è quella del suo oggetto padre.

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

Questo si applica anche alle istanze dell'oggetto elenco basate su QQmlListProperty. Sebbene sia possibile assegnare direttamente tale elenco come input per un modello, si consiglia di evitarlo. Il modello creerà riferimenti non espliciti agli elementi dell'elenco; pertanto, tali elementi saranno ripuliti. Per ottenere i risultati corretti, assegnare prima tutti gli elementi dell'elenco a un elenco locale. Tali riferimenti espliciti saranno mantenuti e non saranno ripuliti. L'esempio riportato di seguito crea un componente list e popola tutti i campi dalla tabella della feature. In seguito, imposta l'elenco come modello di 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;
}

Univocità degli oggetti

Non vi è alcuna garanzia di ottenere lo stesso oggetto, neanche per lo stesso getter o richiamo di funzione. Pertanto, evitare il confronto diretto di oggetti, per esempio:

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)

Proprietà personalizzate su tipi QML

Una proprietà personalizzata (definita dall'utente) è una proprietà che si aggiunge a un'istanza di tipo QML quando la si dichiara. La proprietà non fa parte del tipo ma esiste come proprietà personalizzata sull'istanza specifica. Il linguaggio QML consente di aggiungere proprietà personalizzate alle istanze quando le si dichiara. È possibile aggiungere proprietà personalizzate alle istanze di tipo QML di ArcGIS Runtime, ma tale proprietà potrebbe non essere conservata in tutti i casi per via del modo in cui le istanze vengono mantenute all'interno dell'API. Quindi, evitare di utilizzare proprietà personalizzate su istanze di tipi non supportati.

I seguenti tipi QML, e i tipi da essi derivati, supportano proprietà personalizzate. Altri tipi QML di ArcGIS Runtime non le supportano.

  • ArcGISMapServiceInfo
  • Mappa di base
  • Credenziale
  • FeatureTable
  • Geodatabase
  • GraphicsOverlay
  • LayerContent
  • Mappa
  • Portale
  • PortalTask
  • VectorTileSourceInfo

Lavorare con JSON

Molti tipi QML discendono da JsonSerializable, consentendo così di serializzare il tipo o popolarne i contenuti in JSON. Quando si crea un oggetto da JSON, creare prima un'istanza e quindi passare tale istanza come input al metodo.

Questo codice JavaScript crea e popola un PictureMarkerSymbol da JSON e lo utilizza in una nuova grafica.

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

Lavorare con stringhe tradotte

Tutte le stringhe visualizzate nell'IU di un'app devono usare il formato qsTr() per assicurare che sia possibile globalizzare l'app.

È anche importante considerare le stringhe tradotte quando si definisce la logica dell'app. Se un utente selezionerà un'opzione basata su stringhe nell'IU, ad esempio una selezione da un menu a discesa, ogni caso nell'istruzione switch deve utilizzare la stringa tradotta.

Nel seguente esempio, il pannello di informazioni viene visualizzato quando viene selezionato il menu Informazioni, qualsiasi sia la lingua in cui l'app viene visualizzata:

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

Rendering OpenGL o ANGLE su Windows

Qt ha due motori diversi di rendering per la piattaforma Windows: OpenGL e DirectX tramite ANGLE. Per impostazione predefinita, Qt tenterà il rendering tramite OpenGL. Se non sono disponibili i driver appropriati, continuerà a usare ANGLE per il rendering. Le versioni precedenti di ArcGIS Runtime supportavano solo ANGLE. A partire da ArcGIS Runtime 100.3.0, le app possono supportare perfettamente sia OpenGL che ANGLE; pertanto, è possibile utilizzare qualunque motore di rendering e il meccanismo di fallback di Qt quando non è possibile usare OpenGL su un sistema dato. Per maggiori informazioni, consultare la documentazione di Qt.

Per impostare il rendering OpenGL o ANGLE come predefinito, utilizzare le opzioni Impostazioni > Piattaforme > Windows > Motore di rendering grafico su AppStudio. Non è necessario apportare modifiche al codice.