【问题标题】:QML | Persistent Memory in ListModel (storing ListModel for later use)质量管理体系 | ListModel 中的持久内存(存储 ListModel 供以后使用)
【发布时间】:2020-01-09 07:22:10
【问题描述】:

给定一个具有多层存储信息(存储在元素中的元素数组)的 ListModel,有没有办法存储模型并在以后调用它?

我尝试将 ListModel 存储为 JSON 字符串,但它不跟踪子对象。例如,在下面的 sn-p 中,输出告诉我有一个“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))
        }
    }
}

这是输出,它没有显示有关子对象的任何信息。我希望在“父”对象下有“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"
      }
    ]
  }
]

【问题讨论】:

  • 请问您所说的“存储模型并稍后调用”是什么意思?如果这是我认为的,我不确定字符串化模型是要走的路。至于输出中缺少的属性,当您直接对它们进行字符串化(而不是对包含这些属性的容器对象进行字符串化)时,您会得到什么?
  • 我有一个 ListModel,我在运行时动态更改(使用 .append() 和 .remove() 方法),我希望在关闭程序时保存这些更改,并保留到下一个我打开程序的时间。通常我可以使用 Settings QML 类型轻松地做到这一点,所以我正在做的是对 ListModel 进行字符串化并将字符串存储到 Settings 类型中......但是,存在这个问题:子对象('kids' 和 'ducks ' 在此示例中)不会以字符串化 JSON 结尾,因此我无法在下次打开应用程序并解析数据时检索该数据。
  • 如果我打电话给console.log(JSON.stringify(listModel.get(0).kids)),那么我会得到{"objectName":"","count":2,"dynamicRoles":false},这表明'kids' 数组正在被作为一个对象读取......最不幸的是。尝试console.log(JSON.stringify(listModel.get(0).kids.get(0))) 更好,它至少提供{"kid":"kid1"} 但为整个树创建一个递归循环......如果树是 10 层深,这是一个好习惯吗?如果它有 10 层,那将是一个指数级增长的 for 循环。
  • 确实,树/层次结构越深,序列化整个对象所需的时间就越长。这并不是 JSON.stringify 特有的...更多信息请参阅我即将发布的答案。
  • 您必须深入循环数组才能使用 QML/JS 工具获取其内容 ...

标签: json qt qml listmodel


【解决方案1】:

您似乎想在应用程序关闭时保存模型的当前状态,并在应用程序再次启动时恢复它。序列化和反序列化模型的能力绝对是必须的。

[1/2] 仅基于 Qml 的实现

  1. 使用来自thisthis 序列化程序 SO 回答,假设您不介意绑定到第三方许可证(这个是完全免费的,代码看起来可靠,但我没有尝试或测试过)。然后使用 JSON.parse 从字符串版本重新创建对象。
  2. 制作您自己的(反)序列化程序,并确保它与您正在使用的实际模型紧密结合。例如,如果不是模型中某个对象的所有属性都需要备份/恢复,那么直接查找您需要的属性并仅使用它们可能更明智。这可能会大大降低搜索属性层次结构的开销成本,但您最终会得到一个非常具体的(反)序列化程序,它不能跨项目重用。

[2/2] Qml/C++ 实现

如果时间允许,另一种解决方案是在 C++ 端设计模型并将其按原样或作为 QVariant 公开给 Qml 代码。然后(反)序列化将委托给 C++ 代码。优点是:代码更干净,I/O 操作更快。缺点是:它需要更多的时间来实现,并且在我看来,如果整个应用程序对功能没有要求的话,它会变得不必要地复杂。

【讨论】:

  • 感谢您的回答。我获取了您发布的链接,汲取了灵感,并为我的应用程序创建了一个自定义解决方案。谢谢!
【解决方案2】:

在misterFad 的链接的帮助下,我创建了一个特定于我的应用程序的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"
      }
    ]
  }
]

【讨论】:

    猜你喜欢
    • 2011-12-20
    • 1970-01-01
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多