jsonqtqmllistmodel

QML | Persistent Memory in ListModel (storing ListModel for later use)


Given a ListModel with multiple layers of stored information (arrays of elements stored within elements), is there a way to store the model and recall it later?

I've tried storing ListModel as a JSON string, but it doesn't keep track of child objects. For example, in the following snippet, the output tells me there is a "kids" object, but has no knowledge of "kid1" nor "kid2". Same goes for the "store" object, but no knowledge of "duck1" nor "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))
        }
    }
}

Here is the output, which fails to show any information about the child objects. I would expect there to be "kid1" and "kid2" under the "Parent" object.

[
  {
    "kids": {
      "objectName": "",
      "count": 2,
      "dynamicRoles": false
    },
    "name": "Parent"
  },
  {
    "name": "store",
    "ducks": {
      "objectName": "",
      "count": 2,
      "dynamicRoles": false
    }
  }
]

Edit: I would expect the output to be more like this:

[
  {
    "name": "Parent",
    "kids": [
      {
        "kid": "kid1"
      },
      {
        "kid": "kid2"
      }
    ]
  },
  {
    "name": "store",
    "ducks": [
      {
        "duck": "duck1"
      },
      {
        "duck": "duck2"
      }
    ]
  }
]

Solution

  • It seems you want to save the current state of your model when the application is closed and restore it when the application is started again. Definitely, the ability to serialize and deserialize model is a must here.

    1. Qml-only based implementation

    1. Use this serializer from this SO answer, assuming you don't mind binding to third-party licenses: this one is completely free (same agreements as the MIT license), and the code seems reliable, but I haven't tried or tested it. Then use JSON.parse to recreate objects from their string version.
    2. Craft your own (de)serializer and make sure it's tightly closed to the actual model you're working with. For instance, in case not all of the properties from an object in your model need to be backuped/restored, then it might be wiser to directly look for the properties you need and only play with them. This might considerably lower the overhead cost of searching through the hierarchy of properties, but you'll end up with a very specific (de)serializer which is not reusable across projects.

    2. Qml/C++ implementation

    Time permitting, another solution would be to design the model on C++ side and expose it as is or as QVariant to Qml code. Then (de)serialization will be entrusted to C++ code. The pros are: code is cleaner and I/O operations are faster. Cons are: it needs more time to be implemented and would be unnecessarily complicated in my opinion if the overall application is not feature-demanding.