Melhores práticas do Qt QML

Conforme você continua desenvolvendo aplicativos, você deve saber alguns detalhes que podem fazer seus aplicativos funcionarem melhor e encontrar menos problemas. Este tópico discute detalhes importantes que você deve manter em mente.

Visualização do mapa

O ArcGIS Runtime SDK for Qt oferece três padrões para exibir um mapa em uma visualização de mapa. No AppStudio, você escreverá seu aplicativo em QML, portanto, usará o tipo de mapa MapView.

A API QML da The Qt Company permite que você escreva aplicativos multiplataforma com QML, uma sintaxe declarativa e altamente legível para projetar e construir interfaces de usuário responsivas e fluidas para aplicativos móveis e desktop nativos. O ArcGIS Runtime SDK for Qt estende o QML com tipos de QML que fornece funcionalidade do ArcGIS Runtime. Os objetos são declarados hierarquicamente e possuem propriedades vinculáveis ​​para fornecer comportamento dinâmico automaticamente. As funções JavaScript são usadas para fornecer código procedural quando necessário. Esse é um recurso importante para desenvolvedores que já estão familiarizados com desenvolvimento web e desejam desenvolver aplicativos nativos.

Declare uma Rectangle contendo MapView. No MapView, declare uma Map para exibir e um Viewpoint inicial.

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

Variáveis ​​fortemente tipadas

Ao declarar propriedades em QML, é fácil e conveniente usar o tipo de variável genérica var, no entanto, é sempre melhor usar variáveis ​​fortemente digitadas. Uma variável fortemente tipada declara explicitamente que tipo de dados pode ser armazenado na variável, por exemplo, um inteiro, uma string ou um valor decimal. Variáveis ​​fortemente tipadas podem prevenir a atribuição de valores errados, são mais fáceis de ler e mais fáceis de depurar variáveis ​​comparadas do tipo var. Uma variável do tipo var não impediria que um valor decimal fosse atribuído a ela, mesmo que o valor devesse conter apenas números inteiros.

No exemplo a seguir, a variável inteira intValue recebe inicialmente um valor de 10. Mais tarde no código, a mesma variável é atualizada com um valor de string.

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

Quando esse código é executado, um erro será exibido no console que se refere explicitamente ao número da linha em que o valor da string foi definido e informando Erro: Não é possível atribuir QString a int, tornando o código mais fácil de solucionar.

Se um valor com o tipo errado for atribuído a uma variável do tipo var, um erro não será relatado.

Interfaces de usuário escaláveis

Ao projetar a interface do usuário do seu aplicativo, é importante considerar a variedade em constante evolução de tamanhos de tela e resoluções em que seu aplicativo pode ser usado. Isso pode ser feito incluindo ícones, botões e planos de fundo para cada resolução de exibição ou usando gráficos vetoriais escaláveis ​​(SVG).

Ao incluir um conjunto de imagens em diferentes resoluções, escolha uma convenção de nomenclatura de arquivo que diferencie claramente os tamanhos das imagens. Por exemplo: nome-da-imagem1x.png, nome-da-imagem1.5x.png, nome-da-imagem2x.png representam imagens que são 1 vez DPI base, 1,5 vezes DPI base e 3 vezes DPI base.

Os arquivos SVG são ideais para imagens pequenas, normalmente ícones. Arquivos SVG grandes podem ser lentos para renderizar, então considere usar imagens para planos de fundo.

Para mais informações, consulte Interfaces de usuário escaláveis ​​do Qt.

Depurando seu aplicativo

O AppStudio é construído sobre o Qt Framework, o que significa que você tem acesso a todos os mesmos utilitários de depuração usados ​​com o Qt. Abaixo estão algumas dicas e truques úteis para depurar seus aplicativos Qt.

Utilizando um web proxy da web

Ao depurar aplicativos AppStudio, um utilitário de depuração da web é frequentemente útil para capturar e analisar as solicitações de HTTP que são enviadas e as respostas que são retornadas. Fiddler e Charles são dois exemplos de utilitários de depuração da web utilizados para executar esta tarefa. Você pode usar essas ferramentas para depurar um aplicativo adicionando o seguinte código C ++ em seu aplicativo: QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, "127.0.0.1", 8888));. Este código pode ser definido em tempo de execução e pode estar em seu main.cpp ou em alguma outra classe C ++. Além de utilizar um proxy para depuração, o QNetworkProxy::setApplicationProxy() também pode ser utilizado para especificar o servidor proxy da sua organização. Para fazer isto, especifique a URL e a porta do servidor proxy de sua organização. Mais informações podem ser encontradas na Documentação de NetworkProxy AppFramework.

Utilizando JSON.stringify()

Ao utilizar o método JSON.stringify(), evite passar na referência de objeto propriamente. Utilize a propriedade json do objeto como o parâmetro, por exemplo: JSON.stringify(graphic.geometry.json).

Modelo de memória da QML API

O modelo de memória utilizado para aplicativos QML é baseado em coleta de lixo. As variáveis não referenciadas serão limpas pelo coletor de lixo QML Engine. Portanto, todos os objetos devem ser explicitamente referenciados para evitar coleta de lixo quando eles estiverem ainda em uso.

Criação de objeto utilizando JavaScript

O método ArccGISRuntimeEnvironment.createObject() cria e retorna novas instâncias de um objeto por mecanismo QML. O tempo de vida destas instâncias é determinado pelo objeto principal da instância. Quando o principal é coletado como lixo, o mesmo ocorre com suas instâncias dependentes. Há várias maneiras de persistir uma instância criada com ArccGISRuntimeEnvironment.createObject(), incluindo o seguinte.

  • Você pode especificar o objeto principal no terceiro parâmetro opcional de ArccGISRuntimeEnvironment.createObject().
  • Em seu código declarativo QML, declare o objeto como uma propriedade de outro objeto. Então, no código de JavaScript, instancie o objeto com ArccGISRuntimeEnvironment.createObject(). A classe que contém a propriedade se torna a principal da nova instância. Certifique-se de declarar a propriedade como sendo do mesmo tipo de QML do ArcGIS Runtime que você está instanciando.

Se você não especificar um principal, o JavaScript será definido como o principal da instância do objeto. QML rastreia a instância e a exclui quando não há referências de JavaScript restantes para a instância (ou seja, quando a instância sai do escopo).

Alguns tipos de QML do ArcGIS Runtime incluem um método clone() usado para criar uma instância de objeto desse tipo. Quando você utilizar clone() para criar uma nova instância, o JavaScript será seu principal. Você pode alterar o principal utilizando a propriedade parent.

Trabalhar com modelos

Modelos acessam instâncias de objetos explicitamente. Ao trabalhar com modelos é necessário fornecer dados persistidos para o modelo acessar. Colocar instâncias de objeto recém-criadas diretamente em um QML ListModel não é suficiente para manter o tempo de vida destas instâncias, pois isso não faz referência à contagem destas instâncias. (Consulte a seção anterior sobre a criação de objetos usando JavaScript.) Uma maneira de evitar a coleta de lixo é criar uma propriedade que é uma lista e adicionar as instâncias à lista persistente. O tempo de vida da propriedade list é o de seu principal.

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

Este conceito também se aplica a instâncias de objeto da lista com base no QQmlListProperty. Embora você possa atribuir diretamente esta lista como entrada para um modelo, você deve evitar fazer isto. O modelo criará referências não explícitas aos itens da lista, portanto, os itens serão coletados como lixo. Para obter os resultados corretos, primeiro atribua todos os elementos da lista a uma lista local. Estas referências explícitas irão persistir e evitar coleta de lixo antecipada. O exemplo seguinte constrói um componente list e insere todos os campos a partir da tabela da feição. Então, ele define a lista como o modelo do 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;
}

Singularidade de objeto

Não há nenhuma garantia que você irá obter o mesmo objeto de volta nem o mesmo reprodutor ou chamada de função. Como tal, a comparação direta de objetos deve ser evitada, por exemplo:

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)

Propriedades personalizadas em tipos de QML

Uma propriedade personalizada (definida pelo usuário) é aquela que você adiciona a uma instância de um tipo de QML ao declará-la. A propriedade não faz parte do tipo, mas existe como uma propriedade personalizada na instância específica. A linguagem QML permite a você adicionar propriedades personalizadas a instâncias ao declará-las. Enquanto você puder adicionar propriedades personalizadas nas instâncias do tipo de QML do ArcGIS Runtime for Qt , esta propriedade poderá não ser preservada em todos os casos devido à maneira como as instâncias são mantidas na API. Portanto, evite utilizar propriedades personalizadas em instâncias de tipos que não as suportam.

Os seguintes tipos de QML e os tipos derivados destes tipos oferecem suporte a propriedades personalizadas. Outros tipos de QML do ArcGIS Runtime não.

  • ArcGISMapServiceInfo
  • Mapas Base
  • Credencial
  • FeatureTable
  • Geodatabase
  • GraphicsOverlay
  • LayerContent
  • Mapa
  • Portal
  • PortalTask
  • VectorTileSourceInfo

Trabalhando com JSON

Muitos tipos de QML herdam de JsonSerializable, permitindo que você serialize o tipo ou preencha seu conteúdo em JSON. Ao criar um objeto a partir de JSON, primeiro crie uma instância e, em seguida, passe essa instância como entrada para o método.

Este código de JavaScript cria e preenche um PictureMarkerSymbol de JSON e o utiliza em um novo gráfico.

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

Trabalhando com strings traduzidas

Todas as strings exibidas na interface do usuário de um aplicativo devem usar a formatação qsTr() para garantir que você possa globalizar seu aplicativo.

Também é importante considerar as strings traduzidas ao definir a lógica do seu aplicativo. Se um usuário selecionar uma opção com base em strings na interface do usuário, por exemplo, uma seleção de um menu suspenso, cada caso dentro da instrução switch deverá usar a string traduzida.

No exemplo a seguir, o painel sobre será mostrado quando o item de menu Sobre for selecionado, independentemente do idioma que o aplicativo estiver exibindo:

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

OpenGL ou ANGLE renderizando no Windows

Qt tem dois mecanismos de renderização diferentes para a plataforma Windows: OpenGL e DirectX via ANGLE. Por padrão, o Qt tentará renderizar utilizando OpenGL. Se os drivers apropriados não estiverem disponíveis, ele voltará a utilizar o ANGLE para renderização. Versões anteriores do ArcGIS Runtime suportavam somente ANGLE. A partir do ArcGIS Runtime 100.3.0, seus aplicativos podem suportar totalmente OpenGL e ANGLE para que você possa usar o mecanismo de renderização e mecanismo de fallback do Qt quando o OpenGL não pode ser usado em um determinado sistema. Para mais informações, consulte a Documentação do Qt.

Para escolher entre OpenGL e ANGLE renderizando como um padrão, utilize as opções Configurações > Plataformas > Windows > Mecanismo de Renderização de Gráficos no AppStudio. Nenhuma mudança de código é necessária.