为什么选择QML Model而不是Qt C ++Model?

使用QML时,许多Qt开发人员倾向于认为他们至少应该使用C ++对模型进行编码。实际情况不是这样的:QML经过优化,可以与C ++无缝集成。   

所有QML代码都将编译为具有Native性能的本机代码。并且在使用Qt Quick编译器时,这已经在应用程序的编译期间发生。QML ListModel提供了一个简单的API,并且可以与ListViewGridViewRepeater之类的视图类型完美配合。 

QML最佳实践:为您的ListView使用REST服务和JSON

将QML和JavaScript作为主要的编码语言还有另一个很大的优势:使用REST服务和JSON数据非常容易。 

QML的应用程序逻辑是用JavaScript编写的。因此,QML具有内置支持来处理各种数据类型,例如JSON结构。通过一个简单的HTTP请求,您可以获取JSON数据并在视图中使用它。

以下代码片段从REST服务检索并显示了待办事项列表:

import Felgo 3.0
import QtQuick 2.0

App {
  
  // on app start: fetch data from REST api
  Component.onCompleted: {
    HttpRequest.get("https://jsonplaceholder.typicode.com/todos")
    .timeout(5000)
    .then(function(res) { dataFetched(res.body) })
    .catch(function(err) { console.err("Fetch failed:"+err) });
  }
  
  // dataFetched gets called on success of http request
  function dataFetched(jsonData) {
    listView.model = jsonData // set retrieved json data as model for list
  }
  
  // list page
  NavigationStack {
    Page {
      title: "Todo List"
      
      AppListView {
        id: listView
        anchors.fill: parent
        
        delegate: SimpleRow {
          text: modelData.title
        }
      }
    }
  }
}

      作为ListModel的替代,QML还允许将JSON数据结构分配为模型。使用REST服务时,这非常方便,可以直接使用检索到的JSON结果显示数据。 

rest-service-json-todolist-app

将JSON数据用于ListView模型的缺点

JSON结构不是ListModel,因此也不是QAbstractListModel实现。在这种情况下,您将无法获得高性能C ++模型的好处。另外,JSON数组是一种变体类型。因此,该列表不能期望使用已定义的数据结构创建其元素。    

这导致性能和可用性方面的缺陷。例如,当您更改或替换JSON数据时。然后,视图再次解析整个模型,并从头开始重新绘制所有项目。完全重绘可能需要一段时间,并且用户会注意到。您还会丢失当前的滚动位置,并且不支持高级功能,例如过渡动画。 

此时,您可能会想到:让我们创建一个ListModel并用JSON数据填充它。在解决性能问题的同时,又迅速出现了另一个问题:以后再从API获取新数据时,如何更新模型?  

如果从头开始重新创建ListModel,则视图再次需要完全重绘。为了避免这种情况,我们可以将最新JSON数据的每个条目与ListModel的当前状态进行比较。这仅允许将更改的或新的数据条目同步到模型。   

但是,这样的手动同步需要大量额外的工作。它还会带来一些开销,尤其是当您开始比较大型数据集时。JavaScript和QML不太适合执行此类数据密集型操作。

但是请放心: QML的JsonListModel组件这一特殊的ListModel的实现,可处理JSON数据,完美解决了该问题。    

JsonListModel工作机制

JsonListModel提供了一个简单的方法来转换JSON数据到一个QML的ListModel与使用例如一个AppListView。这是将模型用于待办事项列表示例的方式: 

import Felgo 3.0
import QtQuick 2.0

App {
  
  // on app start: fetch data from REST api
  Component.onCompleted: {
    HttpRequest.get("https://jsonplaceholder.typicode.com/todos")
    .timeout(5000)
    .then(function(res) { dataFetched(res.body) })
    .catch(function(err) { console.err("Fetch failed:"+err) });
  }
  
  // dataFetched gets called on success of http request
  function dataFetched(jsonData) {
    listView.jsonData = jsonData // set retrieved json data as model for list
  }
  
  // list page
  NavigationStack {
    Page {
      title: "Todo List"
      
      AppListView {
        id: listView
        anchors.fill: parent
        
        // property for json data, used as source for JsonListModel
        property var jsonData: []
        
        // use JsonListModel as model
        model: JsonListModel {
          source: listView.jsonData
          keyField: "id"
          fields: ["id", "title"]
        }
        
        // delegate
        delegate: SimpleRow {
          text: title
        }
      }
    }
  }
}

JsonListModel将保存指定的JSON数据的本地副本。只要JSON源发生了变化,数据就会与列表模型的本地副本进行比较。为了标识每个唯一的数据记录,重要的是指定数据对象的keyField。在对新旧数据集进行比较之后,JsonListModel会分别应用所有检测到的更改。因此,它将逐步将模型与更改后的JSON数据同步。      

qsyncable_jsonlistmodel_architecture

JsonListModel类型实现了全QML的ListModel API以及分别发送所有更改的事件。因此,列表视图只能更新相关条目或应用过渡动画。这非常有用,因为您可以例如获取新数据并只需替换旧的JSON。该JsonListModel将检测所有更改,并ListView的更新改变了相应的项目-没有完全重绘。  

JsonListModel的好处

因此,这样可以获得更好的性能,并且在列表更新时滚动保持流畅:   

总而言之,使用JsonListModel可以:  

  • 使用QML和JavaScript从REST API获取JSON数据。
  • 将您的JSON传递给模型,该模型将数据同步到ListModel并为在视图中使用做好准备。  
  • 在您的QML视图中显示模型数据,仅更新已更改的项目。

使用REST API和JSON数据时,无需使用C ++创建自定义模型。该JsonListModel本身就是你的C ++模型。它可以从QML完全使用,并且可以与任何格式的JSON对象一起使用:  

qsyncable_jsonlistmodel_cpp_qml

除了列表视图之外,JsonListModel还支持GridViewRepeater类型来显示模型数据。它是由Ben Lau基于QSyncable实现的可同步C ++模型。可以在GitHub上找到完整的项目。        

JsonListModel还可以提供免费的Felgo SDK。上例中使用的Felgo Apps模块包含许多此类有用的组件。Felgo致力于尽可能简化Qt的移动应用程序开发。例如,用于网络的HttpRequest类型或诸如NavigationStack的UI类型也是SDK的一部分。   

使用SortFilterProxyModel动态排序或过滤数据

为了排序和过滤列表模型,C ++ Qt提供了QSortFilterProxyModel类。同样,您可以将SortFilterProxyModel QML类型与QML中的任何列表模型一起使用。它还可以与JsonListModel结合使用:     

import Felgo 3.0
import QtQuick 2.0

App {
  Page {
    id: page

    // property with json data
    property var jsonData: [
      {
        "id": 1,
        "title": "Apple",
        "type": "Fruit"
      },
      {
        "id": 2,
        "title": "Ham",
        "type": "Meat"
      },
      {
        "id": 3,
        "title": "Bacon",
        "type": "Meat"
      },
      {
        "id": 4,
        "title": "Banana",
        "type": "Fruit"
      }
    ]

    // list model for json data
    JsonListModel {
      id: jsonModel
      source: page.jsonData
      keyField: "id"
      fields: ["id", "title", "type"]
    }

    // SortFilterProxyModel for sorting or filtering lists
    SortFilterProxyModel {
      id: sortedModel
      // use the Component.onCompleted handler to configure SortFilterProxyModel for JsonListModel
      Component.onCompleted: sourceModel = jsonModel
      // add a sorter to sort the list by type
      sorters: StringSorter { id: typeSorter; roleName: "type"; ascendingOrder: true }
    }

    // list view
    AppListView {
      anchors.fill: parent
      model: sortedModel
      delegate: SimpleRow {
        text: model.title
      }
      section.property: "type"
      section.delegate: SimpleSection { }
    }

    // Button change the sorting order
    AppButton {
      anchors.horizontalCenter: parent.horizontalCenter
      anchors.bottom: parent.bottom

      text: "Change Order"
      onClicked: typeSorter.ascendingOrder = !typeSorter.ascendingOrder
    }
  } // Page
}

本示例显示了不同水果和肉类条目的列表。列表条目使用SortFilterProxyModel按类型排序。您还可以通过按AppButton更改排序顺序。  

JsonListModel相似,SortFilterProxyModel是暴露给QML的C ++类型。因此,对于这个简单的QML示例,所有与数据和模型相关的任务实际上都是由C ++类型执行的。使用REST服务和JSON数据时,您可以完全处理所有模型并查看QML中的代码!   

 

   

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值