质量管理语言 | Persistent Memory in ListModel(存储ListModel以备后用)
QML | Persistent Memory in ListModel (storing ListModel for later use)
给定一个具有多层存储信息(存储在元素中的元素数组)的 ListModel,有没有办法存储模型并在以后调用它?
我试过将 ListModel 存储为 JSON 字符串,但它不会跟踪子对象。例如,在下面的代码片段中,输出告诉我有一个 "kids" 对象,但不知道 "kid1" 和 "kid2"。 "store" 对象也是如此,但不知道 "duck1" 或 "duck2".
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
ListModel {
id: listModel
ListElement {
name: "Parent"
kids: [
ListElement {kid: "kid1"},
ListElement {kid: "kid2"}
]
}
ListElement {
name: "store"
ducks: [
ListElement {duck: "duck1"},
ListElement {duck: "duck2"}
]
}
Component.onCompleted: {
var datamodel = []
for (var i = 0; i < this.count; ++i)
datamodel.push(this.get(i))
console.log(JSON.stringify(datamodel))
}
}
}
这是输出,它没有显示有关子对象的任何信息。我希望在 "Parent" 对象下有 "kid1" 和 "kid2"。
[
{
"kids": {
"objectName": "",
"count": 2,
"dynamicRoles": false
},
"name": "Parent"
},
{
"name": "store",
"ducks": {
"objectName": "",
"count": 2,
"dynamicRoles": false
}
}
]
编辑:我希望输出更像这样:
[
{
"name": "Parent",
"kids": [
{
"kid": "kid1"
},
{
"kid": "kid2"
}
]
},
{
"name": "store",
"ducks": [
{
"duck": "duck1"
},
{
"duck": "duck2"
}
]
}
]
您似乎想在应用程序关闭时保存模型的当前状态,并在应用程序再次启动时恢复它。序列化和反序列化模型的能力绝对是这里必须的。
[1/2] 仅基于 Qml 的实现
- 使用 this serializer from this SO 答案,假设您不介意绑定到第三方许可证(这个是完全免费的,代码似乎可靠,但我还没有尝试或测试过)。然后使用
JSON.parse
从字符串版本重新创建对象。
- 制作您自己的(反)序列化器并确保它与您正在使用的实际模型紧密相关。例如,如果模型中某个对象的所有属性都不需要 backuped/restored,那么直接查找您需要的属性并只使用它们可能更明智。这可能会大大降低搜索属性层次结构的开销成本,但您最终会得到一个非常具体的(反)序列化程序,它不能跨项目重用。
[2/2] Qml/C++ 实施
如果时间允许,另一种解决方案是在 C++ 端设计模型并将其按原样或作为 QVariant 公开给 Qml 代码。然后(反)序列化将委托给 C++ 代码。优点是:代码更简洁,I/O 操作更快。缺点是:它需要更多的时间来实施,如果整个应用程序对功能要求不高,我认为它会不必要地复杂。
在 misterFad 的 link 的帮助下,我创建了一个特定于我的应用程序的 serialize() 函数。发布代码以激发其他人的直觉可能会卡在问题上。
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
function serialize(object) {
var model = object
var totalText = "["
for(var i = 0; i < model.count; i++) {
var element = model.get(i)
totalText += "{\"name\": \"" + element.name + "\""
if(element.kids.count) totalText += ",\"kids\": " + serialize(element.kids)
totalText += "}" + (i < model.count-1 ? ",": "")
}
return totalText + "]"
}
ListModel {
id: listModel
ListElement {
name: "dad"
kids: [
ListElement {
name: "kid1";
kids: []
},
ListElement {
name: "kid2";
kids: [
ListElement {name: "grandkid1"; kids: []},
ListElement {name: "grandkid2"; kids: []}
]
}
]
}
ListElement {
name: "store"
kids: [
ListElement {name: "duck1"; kids: []},
ListElement {name: "duck2"; kids: []}
]
}
Component.onCompleted: console.log(serialize(listModel))
}
}
输出JSON是:
[
{
"name": "dad",
"kids": [
{
"name": "kid1"
},
{
"name": "kid2",
"kids": [
{
"name": "grandkid1"
},
{
"name": "grandkid2"
}
]
}
]
},
{
"name": "store",
"kids": [
{
"name": "duck1"
},
{
"name": "duck2"
}
]
}
]
给定一个具有多层存储信息(存储在元素中的元素数组)的 ListModel,有没有办法存储模型并在以后调用它?
我试过将 ListModel 存储为 JSON 字符串,但它不会跟踪子对象。例如,在下面的代码片段中,输出告诉我有一个 "kids" 对象,但不知道 "kid1" 和 "kid2"。 "store" 对象也是如此,但不知道 "duck1" 或 "duck2".
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
ListModel {
id: listModel
ListElement {
name: "Parent"
kids: [
ListElement {kid: "kid1"},
ListElement {kid: "kid2"}
]
}
ListElement {
name: "store"
ducks: [
ListElement {duck: "duck1"},
ListElement {duck: "duck2"}
]
}
Component.onCompleted: {
var datamodel = []
for (var i = 0; i < this.count; ++i)
datamodel.push(this.get(i))
console.log(JSON.stringify(datamodel))
}
}
}
这是输出,它没有显示有关子对象的任何信息。我希望在 "Parent" 对象下有 "kid1" 和 "kid2"。
[
{
"kids": {
"objectName": "",
"count": 2,
"dynamicRoles": false
},
"name": "Parent"
},
{
"name": "store",
"ducks": {
"objectName": "",
"count": 2,
"dynamicRoles": false
}
}
]
编辑:我希望输出更像这样:
[
{
"name": "Parent",
"kids": [
{
"kid": "kid1"
},
{
"kid": "kid2"
}
]
},
{
"name": "store",
"ducks": [
{
"duck": "duck1"
},
{
"duck": "duck2"
}
]
}
]
您似乎想在应用程序关闭时保存模型的当前状态,并在应用程序再次启动时恢复它。序列化和反序列化模型的能力绝对是这里必须的。
[1/2] 仅基于 Qml 的实现
- 使用 this serializer from this SO 答案,假设您不介意绑定到第三方许可证(这个是完全免费的,代码似乎可靠,但我还没有尝试或测试过)。然后使用
JSON.parse
从字符串版本重新创建对象。 - 制作您自己的(反)序列化器并确保它与您正在使用的实际模型紧密相关。例如,如果模型中某个对象的所有属性都不需要 backuped/restored,那么直接查找您需要的属性并只使用它们可能更明智。这可能会大大降低搜索属性层次结构的开销成本,但您最终会得到一个非常具体的(反)序列化程序,它不能跨项目重用。
[2/2] Qml/C++ 实施
如果时间允许,另一种解决方案是在 C++ 端设计模型并将其按原样或作为 QVariant 公开给 Qml 代码。然后(反)序列化将委托给 C++ 代码。优点是:代码更简洁,I/O 操作更快。缺点是:它需要更多的时间来实施,如果整个应用程序对功能要求不高,我认为它会不必要地复杂。
在 misterFad 的 link 的帮助下,我创建了一个特定于我的应用程序的 serialize() 函数。发布代码以激发其他人的直觉可能会卡在问题上。
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
function serialize(object) {
var model = object
var totalText = "["
for(var i = 0; i < model.count; i++) {
var element = model.get(i)
totalText += "{\"name\": \"" + element.name + "\""
if(element.kids.count) totalText += ",\"kids\": " + serialize(element.kids)
totalText += "}" + (i < model.count-1 ? ",": "")
}
return totalText + "]"
}
ListModel {
id: listModel
ListElement {
name: "dad"
kids: [
ListElement {
name: "kid1";
kids: []
},
ListElement {
name: "kid2";
kids: [
ListElement {name: "grandkid1"; kids: []},
ListElement {name: "grandkid2"; kids: []}
]
}
]
}
ListElement {
name: "store"
kids: [
ListElement {name: "duck1"; kids: []},
ListElement {name: "duck2"; kids: []}
]
}
Component.onCompleted: console.log(serialize(listModel))
}
}
输出JSON是:
[
{
"name": "dad",
"kids": [
{
"name": "kid1"
},
{
"name": "kid2",
"kids": [
{
"name": "grandkid1"
},
{
"name": "grandkid2"
}
]
}
]
},
{
"name": "store",
"kids": [
{
"name": "duck1"
},
{
"name": "duck2"
}
]
}
]