qml延迟代码
Many tools rely on web technologies like JavaScript and HTML for mobile app development. But a web view does not offer the performance, features and user experience of native apps.
许多工具都依赖JavaScript和HTML等网络技术来进行移动应用程序开发。 但是,Web视图无法提供本机应用程序的性能,功能和用户体验。
While the Qt framework is C++ based, you can also code with QML and JavaScript. In fact, you can create full apps without even touching C++.
虽然Qt框架基于C ++,但是您也可以使用QML和JavaScript进行编码。 实际上,您甚至无需接触C ++就可以创建完整的应用程序。
This post shows how to save up to 80% of code by choosing QML as your main language. It holds many best practices and tips for creating QML-driven apps that offer the same performance as pure Qt C++ applications. This comprehensive QML development guide summarizes all the knowledge we gathered from creating more than 100 QML-based mobile apps for enterprise customers, startups and own projects.
这篇文章展示了如何通过选择QML作为主要语言来节省多达80%的代码 。 它包含许多创建QML驱动的应用程序的最佳实践和技巧,这些应用程序提供与纯Qt C ++应用程序相同的性能。 这份全面的QML开发指南总结了我们从为企业客户,初创企业和自己的项目创建100多个基于QML的移动应用程序中收集的所有知识。
By reading this guide, you will learn how to avoid C++ models in Qt and develop mobile apps using QML and JavaScript only. These are the main topics covered:
通过阅读本指南,您将学习如何在Qt中避免使用C ++模型并仅使用QML和JavaScript开发移动应用程序。 这些是涵盖的主要主题:
How does the Qt architecture, rendering and compilation work?
Why to use a QML model instead of C++ when working with REST services?
How to add features like offline caching, file downloads or native integrations in QML?
How to structure apps that heavily rely on QML for app logic, models and views?
Qt体系结构:为什么将QML用于iOS或Android应用程序? (The Qt Architecture: Why use QML for iOS or Android Apps?)
In case you have never heard of Qt: It is a powerful and feature-rich C++ framework used in many different industries. It supports development of apps for Desktop, mobile platforms and embedded systems — all from a single code base.
如果您从未听说过Qt:它是一个功能强大且功能丰富的C ++框架,可用于许多不同的行业。 它支持开发用于台式机,移动平台和嵌入式系统的应用程序-所有这些操作都来自一个代码库。
One of the best things about Qt is QML, a reactive programming language (sometimes also referred a declarative language) that extends JavaScript. It allows to create stunning apps that save up to 90% of code compared to native development for iOS or Android. With less code and a single code base for iOS, Android and Desktop, your maintenance costs decrease dramatically. You can release updates to different platforms faster and have one team sharing the knowledge.
关于Qt最好的事情之一是QML ,它是一种扩展JavaScript的React性编程语言 (有时也称为声明性语言 )。 与iOS或Android的本机开发相比,它可以创建惊人的应用程序, 节省多达90%的代码 。 借助更少的代码和针对iOS,Android和桌面的单一代码库,您的维护成本将大大降低。 您可以更快地将更新发布到不同的平台,并让一个团队共享知识。
自定义渲染和QML项目树 (Custom Rendering and QML Item Trees)
In contrast to many other cross-platform solutions, Qt offers an architecture that does not rely on native platform rendering or a web view. It moves all controls and the rendering into the app itself. To show items on the device screen, it only requires a native view with a canvas to draw onto.
与许多其他跨平台解决方案相比,Qt提供的体系结构不依赖本机平台渲染或Web视图。 它将所有控件和渲染移至应用程序本身。 要在设备屏幕上显示项目,只需要一个带有画布的原始视图即可绘制。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/7ae1419ef55f81fe0044d0fbe4e60bc3.png)
This architecture breaks away from the so-called “cookie cutter” apps that have been common in the past. Instead of the native platform renderer, Qt uses app-driven custom rendering. This allows for a unified renderer and app experience across all supported platforms.
该体系结构与过去很常见的所谓“曲奇切割器”应用程序不同。 Qt代替本机平台渲染器,而是使用应用程序驱动的自定义渲染。 这样可以在所有受支持的平台上提供统一的渲染器和应用程序体验。
But don’t let the fact that Qt relies on C++ mislead you. Since the introduction of QML and JavaScript for rapid UI development, you can create item trees in a customizable and extensible way. You can combine and nest individual QML Items to form a tree that describes your UI. There’s no need to dive into complex C++ code!
但是不要让Qt依赖C ++的事实误导您。 由于引入了用于快速UI开发的QML和JavaScript ,您可以以可定制和可扩展的方式创建项目树。 您可以合并并嵌套各个QML项,以形成描述您的UI的树。 无需深入研究复杂的C ++代码!
This is how the code for a simple QML app with a “Hello World!” page looks like:
这就是带有“ Hello World!”的简单QML应用程序的代码。 页面看起来像:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/7131bee741bef3a5771dbebddb8b1923.png)
本机性能和视图代码的编译 (Native Performance and Compilation of View Code)
In the background, each QML Item uses a performant native C++ implementation. When the Qt runtime parses your QML code, it creates all QML Items as C++ objects. With your QML markup and JavaScript logic, you can control and combine them. This makes it easy to build your UI.
在后台,每个QML项目都使用高性能的本机C ++实现。 当Qt运行时解析您的QML代码时,它将所有QML项目创建为C ++对象。 使用QML标记和JavaScript逻辑,您可以控制和组合它们。 这样可以轻松构建UI。
There’s no need to create your UI with C++ widgets. Apps created with QML offer the same performance. Qt compiles your QML tree as soon as it parses the code the first time. You get this Just-in-Time (JIT) compilation of QML apps out-of-the-box.
无需使用C ++小部件创建UI。 使用QML创建的应用程序具有相同的性能。 Qt会在第一次解析代码时立即编译您的QML树。 您可以立即获得QML应用程序的即时(JIT)编译。
![Image for post](https://miro.medium.com/max/9999/0*4_MshqgYon_jqHh8.jpg)
With the Qt Quick Compiler, you can also compile your QML code Ahead-of-Time (AOT). It transforms your QML and JavaScript directly into bytecode. This architecture makes apps powered by QML super fast and performant.
使用Qt快速编译器 ,您还可以提前编译QML代码(AOT) 。 它将QML和JavaScript直接转换为字节码。 这种体系结构使基于QML的应用程序变得超级快速和高性能。
Qt MVC:QML中的模型和视图 (Qt MVC: Models and Views in QML)
For most apps, it is a basic task to populate UI views based on some application data. Qt offers a built-in separation into model, view and delegate components. The following example visualizes a set of data records in a list:
对于大多数应用程序来说,根据一些应用程序数据填充UI视图是一项基本任务。 Qt提供了对模型,视图和委托组件的内置分离。 以下示例将列表中的一组数据记录可视化:
import Felgo 3.0
import QtQuick 2.0
App {
// data model
ListModel {
id: fruitModel
ListElement {
name: "Banana"
cost: 1.95
}
ListElement {
name: "Apple"
cost: 2.45
}
ListElement {
name: "Orange"
cost: 3.25
}
}
// list page
NavigationStack {
Page {
title: "List Page"
AppListView {
anchors.fill: parent
model: fruitModel
delegate: SimpleRow {
text: name
detailText: "cost: "+cost
}
} // AppListView
} // Page
} // NavigationStack
} // App
The AppListView presents you with a scrollable list view. For each ListElement in your ListModel, the view instantiates the delegate Item to visualize each element in your list. In this case, a SimpleRow item represents each list element.
AppListView为您提供可滚动的列表视图。 对于ListModel中的每个ListElement ,该视图实例化委托 Item以可视化列表中的每个元素。 在这种情况下, SimpleRow项代表每个列表元素。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/d6ab41fe7bd5e36eb860b93f2da288e4.png)
The ListModel type is actually a C++ QAbstractListModel implementation exposed to QML. The above code does not only create a UI tree of C++ objects. It also handles the list data in a C++ data structure — pretty nice!
ListModel类型实际上是公开给QML的C ++ QAbstractListModel实现。 上面的代码不仅创建了C ++对象的UI树。 它还以C ++数据结构处理列表数据-很好!
It is very fast to develop user interfaces this way. And as C++ is actually used under the hood, there is no performance drawback. Still, for long-running, heavy-weight and data-intense calculations it makes sense to move away from QML. In such cases, C++ will outperform JavaScript. For more examples when mixing both languages is worth the extra effort, keep on reading this article. We’ve got you covered with details how to combine C++ code with QML as well!
以这种方式开发用户界面非常快。 并且由于C ++实际上是在后台使用的,因此没有性能上的缺点。 尽管如此,对于长时间运行,重量级和数据密集型计算,还是有必要摆脱QML。 在这种情况下,C ++将胜过JavaScript。 有关混合使用两种语言值得付出额外努力的更多示例,请继续阅读本文。 我们已经为您详细介绍了如何将C ++代码与QML相结合!
为什么选择QML ListModel而不是Qt C ++模型? (Why Choose a QML ListModel instead of a Qt C++ Model?)
When using QML, many Qt developers tend to believe they should at least code the model in C++. This is not the case. QML is optimized to integrate seamlessly with C++.
使用QML时,许多Qt开发人员倾向于认为他们至少应该使用C ++对模型进行编码。 事实并非如此。 QML经过优化,可以与C ++无缝集成。
All QML code gets compiled to native code with native performance. And when using the Qt Quick Compiler, this already happens during compilation of the app. The QML ListModel offers a simple API and perfectly works together with view types like ListView, GridView or Repeater.
所有QML代码都将编译为具有本机性能的本机代码。 并且在使用Qt快速编译器时 ,这已经在应用程序的编译期间发生。 QML ListModel提供了一个简单的API,并且可以与ListView , GridView或Repeater之类的视图类型完美配合。
QML最佳实践:为您的ListView使用REST服务和JSON (QML Best Practice: Use REST Services and JSON for your ListView)
There is another big advantage of using QML and JavaScript as your main coding language: It is super easy to work with REST services and JSON data.
使用QML和JavaScript作为主要的编码语言还有另一个很大的优势:使用REST服务和JSON数据非常容易。
The application logic for QML gets written in JavaScript. QML thus has built-in support to handle variant data types like JSON structures. With a simple HTTP request, you can fetch JSON data and use it in your views.
QML的应用程序逻辑使用JavaScript编写。 因此,QML具有内置支持来处理各种数据类型,例如JSON结构。 通过简单的HTTP请求,您可以获取JSON数据并在视图中使用它。
The following code snippet retrieves and shows a list of todo entries from a REST service:
以下代码片段检索并显示了来自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
}
}
}
}
}
Instead of a ListModel, QML also allows you to assign JSON data structures as the model. This is very convenient when working with REST services. You can directly use the retrieved JSON result to display your data.
QML代替ListModel ,还允许您将JSON数据结构分配为模型。 使用REST服务时,这非常方便。 您可以直接使用检索到的JSON结果显示数据。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/af2e168860e33be49df7be9f7bbc5c40.png)
将JSON数据用于ListView模型的缺点 (Drawbacks of Using JSON data for the ListView Model)
A JSON structure is no ListModel and thus no QAbstractListModel implementation. You do not have the benefits of a performant C++ model in this case. Also, a JSON array is a variant type. The list can thus not expect a defined data structure to create its elements.
JSON结构不是ListModel ,因此也不是QAbstractListModel实现。 在这种情况下,您将无法获得高性能C ++模型的好处。 另外,JSON数组是一种变体类型。 因此,该列表不能期望已定义的数据结构创建其元素。
This results in performance and usability drawbacks. For example, when you change or replace the JSON data. The view then parses the whole model again and redraws all items from scratch. This full redraw can take a while and is noticeable by the user. You also lose the current scroll position and advanced features like transition animations are not supported.
这导致性能和可用性方面的缺陷 。 例如,当您更改或替换JSON数据时。 然后,视图再次解析整个模型,并从头开始重新绘制所有项目。 完全重绘可能需要一段时间,并且用户会注意到。 您还会丢失当前的滚动位置,并且不支持高级功能,例如过渡动画。
At this point, you could think: Let’s create a ListModel and fill it with the JSON data. While this solves the performance problem, another issue quickly pops up: How do you update the model when you fetch new data from the API at a later point?
此时,您可能会想到:让我们创建一个ListModel并用JSON数据填充它。 在解决性能问题的同时,又Swift出现了另一个问题:以后再从API获取新数据时,如何更新模型?
If you re-create the ListModel from scratch, the view again requires a full redraw. To avoid this, we could compare each entry of the latest JSON data with the current state of the ListModel. This allows to only synchronize changed or new data entries to the model.
如果从头开始重新创建ListModel ,则视图再次需要完全重绘。 为了避免这种情况,我们可以将最新JSON数据的每个条目与ListModel的当前状态进行比较。 这仅允许将更改的或新的数据条目同步到模型。
But such a manual synchronization requires a lot of extra effort. It also comes with some overhead, especially when you start to compare large data sets. JavaScript and QML are not well suited to perform such data-intense operations.
但是,这种手动同步需要大量额外的精力。 它还会带来一些开销,尤其是当您开始比较大型数据集时。 JavaScript和QML不太适合执行此类数据密集型操作。
But don’t worry: The next section introduces a QML component that covers exactly this synchronization. The JsonListModel is a special ListModel implementation that can handle JSON data.
但是请放心:下一部分将介绍一个QML组件,该组件恰好涵盖了这种同步。 JsonListModel是一个特殊的ListModel实现,可以处理JSON数据。
JsonListModel如何工作? (How Does the JsonListModel Work?)
The JsonListModel offers an easy way to transform JSON data into a QML ListModel for usage with e.g. an AppListView. This is how you can use the model for our todo list example:
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
}
}
}
}
}
The JsonListModel holds a local copy of the specified JSON data. Whenever the JSON source changes, the data gets compared to the local copy of the list model. To identify each unique data record, it is important to specify the keyField of your data objects. After diffing the old and new data sets, the JsonListModel applies all detected changes individually. It thus synchronizes the model with the changed JSON data step by step.
JsonListModel保存指定的JSON数据的本地副本。 只要JSON源发生更改,就将数据与列表模型的本地副本进行比较。 为了标识每个唯一的数据记录,重要的是指定数据对象的keyField 。 在对新旧数据集进行比较之后, JsonListModel会分别应用所有检测到的更改。 因此,它将逐步将模型与更改后的JSON数据同步。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/d253d7aec70d8da277b835165ef1d444.png)
The JsonListModel type implements the full QML ListModel API and fires separate events for all changes. The list view can thus only update relevant entries or apply transition animations. This is super useful, as you can e.g. fetch new data and simply replace the old JSON. The JsonListModel will detect all changes, and the ListView updates changed items accordingly — without a full redraw.
JsonListModel类型实现完整的QML ListModel API,并为所有更改触发单独的事件。 因此,列表视图只能更新相关条目或应用过渡动画。 这非常有用,因为您可以例如获取新数据并仅替换旧的JSON。 JsonListModel将检测所有更改,并且ListView相应地更新更改的项目-无需完全重绘。
JsonListModel的好处 (Benefits of JsonListModel)
You thus get a much better performance and scrolling stays smooth when the list updates:
因此,您可以获得更好的性能,并且列表更新时滚动保持流畅 :
Json Model: The list jumps to the top after a model update.
Json模型 :更新模型后,列表跳至顶部。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/f1990e1bdce8ebc2181bf6f2a6521d55.png)
JsonListModel: The list keeps its scroll position. (the GIF only jumps to the top when it restarts)
JsonListModel :列表保持其滚动位置。 (GIF仅在重新启动时才跳到顶部)
![Image for post](https://miro.medium.com/freeze/max/9999/0*ALD7U1A1oRGTLCeZ.gif)
To summarize, with the JsonListModel you can:
总而言之,使用JsonListModel可以:
- Fetch JSON data from REST APIs with QML and JavaScript. 使用QML和JavaScript从REST API获取JSON数据。
Pass your JSON to the model, which synchronizes the data to a ListModel and prepares it for usage in your view.
将您的JSON传递给模型,该模型将数据同步到ListModel并为在视图中使用做好准备。
- Show the model data in your QML view, which now only updates items that changed. 在您的QML视图中显示模型数据,现在仅更新已更改的项目。
You do not require to create a custom model in C++ when working with REST APIs and JSON data. The JsonListModel itself is your C++ model. It is fully usable from QML and can work with JSON objects of any format:
使用REST API和JSON数据时,无需使用C ++创建自定义模型。 JsonListModel本身就是您的C ++模型。 它可以从QML完全使用,并且可以与任何格式的JSON对象一起使用:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/8bb17ffad4781bc81ea359011c24bd9d.png)
Apart from list views, the JsonListModel also supports the GridView and Repeater types to display model data. It is based on QSyncable, a syncable C++ model implementation by Ben Lau. You can find the full project on GitHub.
除了列表视图之外, JsonListModel还支持GridView和Repeater类型来显示模型数据。 它基于QSyncable ,它是Ben Lau的可同步C ++模型实现。 您可以在GitHub上找到完整的项目。
The JsonListModel is also available with the free Felgo SDK. The Felgo Apps module used in the above example holds many such useful components. Felgo focuses on making mobile app development with Qt as easy as possible. For example, the HttpRequest type for networking or UI types like NavigationStack are also part of the SDK.
该JsonListModel还可以提供免费的Felgo SDK。 上例中使用的Felgo Apps模块包含许多此类有用的组件。 Felgo致力于尽可能简化Qt的移动应用开发。 例如,用于网络的HttpRequest类型或诸如NavigationStack的 UI类型也是SDK的一部分。
使用SortFilterProxyModel动态排序或过滤数据 (Dynamically Sort or Filter Data with SortFilterProxyModel)
To sort and filter list models, C++ Qt offers the QSortFilterProxyModel class. In the same way, you can use the SortFilterProxyModel QML type with any list model in QML. It also works in conjunction with the JsonListModel:
为了排序和过滤列表模型,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
}
This example shows a list of different fruit and meat entries. The list entries get sorted by type with the SortFilterProxyModel. You can also change the sorting order by pressing the AppButton.
本示例显示了不同水果和肉类条目的列表。 列表条目使用SortFilterProxyModel按类型排序。 您还可以通过按AppButton更改排序顺序。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/3b0e600de05151d4a31678fe6ee024d7.png)
Similar to JsonListModel, the SortFilterProxyModel is a C++ type exposed to QML. So for this simple QML example, all data and model-related tasks are actually performed by C++ types. When working with REST services and JSON data, you can fully handle all model and view code in QML!
与JsonListModel相似, SortFilterProxyModel是暴露给QML的C ++类型。 因此,对于这个简单的QML示例,所有与数据和模型相关的任务实际上都是由C ++类型执行的。 使用REST服务和JSON数据时,您可以完全处理所有模型并查看QML中的代码!
您的移动应用程序的离线缓存,文件下载和本机集成 (Offline Caching, File Downloads and Native Integrations for your Mobile App)
It is very simple to create stunning views and handle application data with QML. But why stop there? Let’s take it even one step further!
使用QML创建惊人的视图并处理应用程序数据非常简单。 但是为什么要停在那里? 让我们更进一步!
从QML控制您的应用程序 (Control Your Application from QML)
As QML and C++ integrate seamlessly, it is possible to expose any native feature for usage with QML. Available Qt components already allow to work with sensors, SQLite databases and much more. And the Felgo SDK offers lots of additional features. For example to fetch assets at runtime with the DownloadableResource item. It allows you to keep the initial app size small and dynamically load content if required — all with QML.
由于QML和C ++无缝集成,因此可以公开任何本机功能以供QML使用。 可用的Qt组件已经允许与传感器,SQLite数据库等一起使用。 Felgo SDK提供了许多附加功能。 例如,在运行时使用DownloadableResource项目获取资产。 它使您可以保持初始应用程序的大小很小,并在需要时动态加载内容-全部使用QML。
You can create your own C++ components and register them with QML as well. For iOS and Android apps, you can even add components that
您可以创建自己的C ++组件,也可以向QML注册它们。 对于iOS和Android应用,您甚至可以添加用于
- weave-in native iOS code with Obj-C 使用Obj-C编织本机iOS代码
- or run Java Android code over JNI. 或通过JNI运行Java Android代码。
Please note that such native code requires custom implementations for each platform then. Felgo already has you covered with the NativeUtils component. It offers lots features like native dialogs, camera and image picker or sharing. The SDK also comes with many Felgo Plugins that integrate 3rd party frameworks for:
请注意,这样的本地代码需要为每个平台自定义实现。 Felgo已经为您提供了NativeUtils组件。 它提供了很多功能,例如本机对话框,相机和图像选择器或共享。 该SDK还附带了许多Felgo插件 , 这些插件集成了第三方框架以实现:
- server-triggered or local notifications 服务器触发或本地通知
- in-app purchases and monetization 应用内购买和货币化
- analytics and crash reporting 分析和崩溃报告
- Firebase authentication and database Firebase身份验证和数据库
- and much more. 以及更多。
There is no limit to what you can do — it’s possible to manage your full app logic purely with QML. You can even perform calculations in different threads with a WorkerScript.
您可以做什么没有任何限制-可以完全使用QML管理完整的应用程序逻辑。 您甚至可以使用WorkerScript在不同的线程中执行计算。
带有JsonListModel和离线缓存的应用示例 (App Example with JsonListModel and Offline Caching)
Mobile apps have to work properly even without internet access. The Storage component allows to cache data in a simple key-value store. It can save full JSON structures as well. The data gets serialized and converted to string format automatically.
即使没有互联网访问,移动应用也必须能够正常运行。 存储组件允许将数据缓存在简单的键值存储中。 它也可以保存完整的JSON结构。 数据被序列化并自动转换为字符串格式。
You can thus use the Storage to initialize the JsonListModel with previously cached JSON data. This way, your app can show the latest state of the data even if a fetch request fails:
因此,您可以使用Storage来使用先前缓存的JSON数据初始化JsonListModel 。 这样,即使获取请求失败,您的应用也可以显示数据的最新状态:
import Felgo 3.0
import QtQuick 2.0
App {
// on app start: fetch data
Component.onCompleted: {
fetchData()
}
// 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
}
}
}
}
// storage for caching
Storage {
id: cache
}
// fetch data from cache or from api
function fetchData() {
// check cached value first
var cachedData = cache.getValue("todos")
if(cachedData)
listView.jsonData = cachedData
// load new data from api
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) {
// cache new data before updating the model
cache.setValue("todos", jsonData)
listView.jsonData = jsonData // set retrieved json data as model for list
}
}
In addition to fetched data, you can locally cache new entries as well. As soon as the app has internet connection again, save them to your server and remove the local entries.
除了获取数据之外,您还可以在本地缓存新条目。 该应用程序再次与Internet连接后,将它们保存到您的服务器并删除本地条目。
We prepared a full demo app for you, which allows to browse and create todo list entries. You can find the full example with caching, local draft entries, list filtering and more on GitHub:
我们为您准备了完整的演示应用程序,可以浏览和创建待办事项列表条目。 您可以在GitHub上找到有关缓存,本地草稿条目,列表过滤等的完整示例:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/3ef28665693e8ae68a754f123c5d0320.png)
何时使用C ++和何时使用QML (When to Use C++ and When to Use QML)
Application Development with QML is simple and powerful. But Qt C++ can be more performant, offers many features and is less error-prone. So it’s important to know when to use which.
使用QML进行应用程序开发既简单又强大。 但是Qt C ++可以具有更高的性能,提供许多功能并且不容易出错。 因此,重要的是要知道何时使用。
Coding in QML has several advantages over development with C++:
与使用C ++进行开发相比 ,QML中的编码具有多个优势 :
- Coding with QML + JavaScript is very easy to learn and allows to reduce the required amount of code a lot. 使用QML + JavaScript进行编码非常容易学习,并且可以大大减少所需的代码量。
- Language concepts like states, signals or property bindings are a huge time-saver. 语言概念(例如状态,信号或属性绑定)可节省大量时间。
- QML makes adding animations simple. You can animate every property of your QML types with simple Animation components. QML使添加动画变得简单。 您可以使用简单的Animation组件为QML类型的每个属性设置动画。
- QML is extensible and flexible. For example, you can extend objects with new properties and features in-line. No need to create a new re-usable type for small extensions. QML具有可扩展性和灵活性。 例如,您可以内联扩展具有新属性和功能的对象。 无需为小型扩展创建新的可重用类型。
- The QML Rendering Engine offers a great performance. The renderer uses C++ Qt and relies on a hardware accelerated scene graph. This makes it fast enough to power even high-performance games. QML渲染引擎提供了出色的性能。 渲染器使用C ++ Qt并依赖于硬件加速的场景图。 这使得它足够快,甚至可以支持高性能游戏。
Qt app development with C++ has advantages as well. For some scenarios you need features that are only available with Qt C++. Also, C++ is fast and type-safe. This allows to provide the best possible performance for long-running and data-intense calculations.
使用C ++开发Qt应用程序也具有优势。 在某些情况下,您需要仅Qt C ++可用的功能。 同样,C ++快速且类型安全。 这样可以为长时间运行和数据密集型计算提供最佳性能。
For these examples, you would choose C++ over QML:
对于这些示例,您将选择C ++而不是QML :
- Native C++ code is the right choice for data-intense operations. It will outperform interpreted QML/JavaScript code. 本地C ++代码是数据密集型操作的正确选择。 它将胜过解释后的QML / JavaScript代码。
- C++ code is type-safe and compiled into object code. For parts where stability and security are important, using C++ helps to make your app less error-prone. C ++代码是类型安全的,并已编译为目标代码。 对于稳定性和安全性很重要的部分,使用C ++可以使您的应用程序不易出错。
- The Qt C++ components offer different and in some cases more features than the QML types. For example, advanced networking features. 与QML类型相比,Qt C ++组件提供了不同的功能,在某些情况下还提供了更多的功能。 例如,高级联网功能。
- It is also possible to mix C++ with native code for Android (over JNI) or iOS (Obj-C or Swift). This allows to provide such native functionality for QML as well. 也可以将C ++与Android(通过JNI)或iOS(Obj-C或Swift)的本机代码混合使用。 这也允许为QML提供这种本机功能。
- You might need a 3rd party library that is only available in C++, or have existing code in C++ which you’d like to reuse. 您可能需要仅在C ++中可用的第3方库,或者想要重用的C ++中已有的代码。
It is possible to code most parts of the application without the need to touch C++. The Felgo SDK and Qt have many QML components available. For a starting point to integrate Qt C++ or make native features available for QML, you can see the guide How to Expose a Qt C++ Class with Signals and Slots to QML.
无需触摸C ++就可以对应用程序的大部分进行编码。 Felgo SDK和Qt有许多可用的QML组件。 有关集成Qt C ++或使本机功能可用于QML的起点,请参阅指南如何将带有信号和插槽的Qt C ++类公开到QML 。
QML MVC:应用程序架构最佳实践和设计模式 (QML MVC: App Architecture Best Practices and Design Patterns)
With all this knowledge and QML benefits in mind, we will use QML for more than only view code. We handle data-related tasks and application logic as well. It thus becomes very important to think about a clean app architecture and component structure for such QML-driven apps. We want to keep our code clean, maintainable and extensible.
考虑到所有这些知识和QML的好处,我们将QML不仅用于查看代码。 我们还处理与数据相关的任务和应用程序逻辑。 因此,为此类QML驱动的应用程序考虑一个干净的应用程序体系结构和组件结构就变得非常重要。 我们希望保持代码的清洁,可维护和可扩展。
为什么要关心分离关注点? (Why care about separation of concerns?)
The easiness and flexibility of QML can lead to problems. When using signals and property bindings a simple value change can affect many components. Properties that rely on other properties update automatically. They handle the signal and update their value as well. This is even possible across multiple QML Items:
QML的简便性和灵活性可能导致问题。 使用信号和属性绑定时 ,简单的值更改可能会影响许多组件。 依赖其他属性的属性会自动更新。 他们处理信号并更新其值。 甚至可以在多个QML项目中实现:
![Image for post](https://miro.medium.com/max/9999/0*g3MM-_2VHNjZ2rSV.jpg)
This doesn’t look complex now. But imagine that we add a few new components with different properties and cross-dependencies:
现在看起来并不复杂。 但是,假设我们添加了一些具有不同属性和交叉依赖关系的新组件:
![Image for post](https://miro.medium.com/max/9999/0*7GTD9z3xv375MVR6.jpg)
Different connections between all the items form. You can no longer say for sure what effect a single property change may have for directly or indirectly connected components. In the worst case, this can result in circular dependencies or loops. If you face such issues, this is an indicator for bad component architecture.
所有项目之间形成不同的联系。 您不再可以肯定地说单个属性更改可能对直接或间接连接的组件产生什么影响。 在最坏的情况下,这可能会导致循环依赖性或循环。 如果遇到此类问题,则表明组件体系结构不良。
This problem gets bigger and bigger the more your project grows. Each component should thus have a clean interface and only manage its own data. This is what separation of concerns means.
随着项目的增长,这个问题变得越来越大。 因此,每个组件应具有干净的界面,并且仅管理自己的数据。 这就是关注点分离的含义。
MVC,MVVM或Flux(React Native)等设计模式 (Design Patterns like MVC, MVVM or Flux (React Native))
A bad component architecture can quickly lead to unwanted side-effects or corrupted data. Imagine lots of signals firing and event handlers running in unknown order. Your code at different parts of the app changes data seemingly random or with duplicated code. This is a nightmare for debugging, maintenance or refactoring.
不良的组件体系结构会Swift导致不良的副作用或数据损坏。 想象一下,许多信号触发和事件处理程序以未知顺序运行。 您在应用程序不同部分的代码似乎会随机更改数据或使用重复的代码更改数据。 这是调试,维护或重构的噩梦。
For most design patterns, the golden rule is: Keep the code that displays data (view) separate from the code that reads or modifies data (model).
对于大多数设计模式,黄金法则是:将显示数据(视图)的代码与读取或修改数据(模型)的代码分开。
QML中的模型视图分离 (Model-View Separation in QML)
Each content view of a Felgo app is usually composed as a Page. The Page type is a view controller, which provides and displays data for the user. By introducing a DataModel component, we can move data handling away from the view:
Felgo应用程序的每个内容视图通常都由一个页面组成。 Page类型是一种视图控制器,它为用户提供并显示数据。 通过引入DataModel组件,我们可以将数据处理从视图中移开:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/9116d4827904eb85593d84d3d9b39634.png)
The DataModel is your central storage for application data. Pages can only access application data with the DataModel. It manages your data in a way that makes sense for your use-case and views. For different views and use-cases, the usage of several DataModel components is possible.
DataModel是应用程序数据的中央存储。 页面只能使用DataModel访问应用程序数据。 它以对您的用例和视图有意义的方式来管理数据。 对于不同的视图和用例,可以使用多个DataModel组件。
For the app logic, you will also add many functions and signal handlers to your view or model. If not done properly, this results in a lot of fragmented code spread across view items. Once your application gets more complex, it also gets more difficult to maintain your code clean and testable. It gets hard to decide where to perform which action, and duplicate code spread across pages is inevitable.
对于应用程序逻辑,您还将在视图或模型中添加许多功能和信号处理程序。 如果处理不当,则会导致许多分散的代码分散在视图项中。 一旦您的应用程序变得更加复杂,维护代码干净和可测试的难度也就增加了。 很难决定在哪里执行哪个操作,并且不可避免地会在页面之间分布重复的代码。
With the above architecture, the data flow between model and page is bi-directional. This means, pages do not only show model data, but can also write to the model directly. Modern application frameworks like React Native use a different approach. For example, the Flux architecture designed by Facebook favors an unidirectional data flow.
使用上述架构,模型和页面之间的数据流是双向的。 这意味着页面不仅显示模型数据,还可以直接写入模型。 像React Native这样的现代应用程序框架使用了不同的方法。 例如,Facebook设计的Flux架构偏向于单向数据流。
创建干净的数据流:受Flux启发的QML架构 (Create a clean Data Flow: QML Architecture inspired by Flux)
With Flux, each user interaction propagates the action through a central dispatcher. The dispatcher forwards the action to various stores that hold application data and business logic:
使用Flux,每个用户交互都会通过中央调度程序传播操作。 调度程序将操作转发到保存应用程序数据和业务逻辑的各种存储:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/973349fd8dfc41bb08105b7a362930c2.png)
You can read more about a quite sophisticated implementation of such a pattern for QML in this post by Ben Lau: Revised QML Application Architecture Guide with Flux
您可以在Ben Lau的这篇文章中了解有关QML这种模式的相当复杂的实现的更多信息: 带Flux的修订版QML应用程序体系结构指南
It’s hard to say if the overhead of a complex solution is worth the effort. For most mobile app projects, a more relaxed implementation with the same advantages is sufficient.
很难说复杂解决方案的开销是否值得付出努力。 对于大多数移动应用程序项目,具有相同优势的更轻松的实现就足够了。
QML中用于模型视图控制器分离的简单类流量示例 (Simple Flux-like Example for Model View Controller Separation in QML)
To create a one-directional data flow, we can also take advantage of QML’s built-in signal mechanism. We can ensure a loose coupling between different components. You can find a basic example architecture that applies this pattern in this guide: Separation of Model, View and Logic Code in your Qt App using QML
为了创建单向数据流,我们还可以利用QML的内置信号机制。 我们可以确保不同组件之间的松散耦合。 您可以在本指南中找到一种适用于此模式的基本示例架构: 使用QML在Qt App中分离模型,视图和逻辑代码
It introduces a Logic component to dispatch actions from Pages to the DataModel:
它引入了一个Logic组件来将动作从Pages调度到DataModel:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/2b369a95fb89977ef6aa444520716a8a.png)
Doing a lot of work in QML can quickly result in unreadable and fragmented code. With a clean component architecture and clear responsibilities, you can avoid this. Using an architecture like above helps to provide a consistent app structure that simplifies testing and refactoring.
在QML中进行大量工作会很快导致不可读和零散的代码。 有了干净的组件体系结构和明确的职责,您可以避免这种情况。 使用上述架构有助于提供一致的应用程序结构,从而简化测试和重构。
With the principles shown in this guide, you can create well-structured apps that handle app logic, data-related tasks and view code purely with QML.
借助本指南中显示的原理,您可以创建结构良好的应用程序,这些应用程序可以处理应用程序逻辑,与数据相关的任务并仅使用QML来查看代码。
Not sure how to get started? Felgo offers many demos and examples you can use to build a first prototype of your project:
不知道如何开始? Felgo提供了许多演示和示例 ,可用于构建项目的第一个原型:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/7e92acd4b70f692db18dbff3cb776c49.png)
We can also help you out with Qt Trainings and App Development Workshops to get your team started!
我们还可以通过Qt培训和应用开发研讨会帮助您,使您的团队开始!
![Image for post](https://miro.medium.com/max/9999/0*Ca8GxCWQ9vHG_OjU.png)
The Felgo SDK is free to use, so make sure to check it out!
Felgo SDK是免费使用的,因此请务必检查一下!
Do you already have a project or app idea in mind? The Felgo team is here to support you! We can cover the whole process from the first idea up to the release of your app in the stores. Take advantage of our Mobile App Development Services and join the ranks of satisfied Felgo customers:
您已经有了一个项目或应用程序构想吗? Felgo团队在这里为您提供支持! 我们可以涵盖从最初构想到商店中发布您的应用程序的整个过程。 充分利用我们的移动应用开发服务,并加入满意的Felgo客户的行列:
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/c0ad49dee07e249e086b4d6b07e93539.png)
If you enjoyed this post, feel free to share it on Facebook or Twitter.
如果您喜欢这篇文章,请随时在Facebook或Twitter上分享。
更多相关的应用开发资源 (More Relevant App Development Resources)
Separation of Model, View and Logic Code in your Qt App using QML
最佳应用开发教程和免费应用模板 (The Best App Development Tutorials & Free App Templates)
All of these tutorials come with full source code of the mobile apps! You can copy the code to make your own apps for free!
所有这些教程都附带了移动应用程序的完整源代码! 您可以复制代码以免费制作自己的应用!
How to create a mobile app for iOS & Android with a single code base
How to support multiple languages and internationalization in your mobile app
How to support multiple screen sizes & screen densities — Responsive App Guide
应用开发视频教程 (App Development Video Tutorials)
Make Cross-Platform Apps with Qt: Felgo Apps
How to Add In-App Chat or Gamification Features to Your Mobile App
How to Make a Mobile App with Qt Quick Designer (QML Designer) & Felgo
如何使用Qt Quick Designer(QML Designer)和Felgo制作移动应用
Originally published at https://felgo.com on April 4, 2020.
最初于 2020年4月4日 在 https://felgo.com 上 发布 。
翻译自: https://medium.com/swlh/choose-qml-over-c-cut-your-code-by-80-f711111a65e2
qml延迟代码