简体   繁体   中英

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"
      }
    ]
  }
]

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

[1/2] 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 totally free 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 hierarchy of properties but you'll endup with a very specific (de)serializer which is not reusable across projects.

[2/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.

With the help of misterFad's link, I created a serialize() function that is specific to my application. Posting the code to spark intuition in others potentially stuck on the problem.

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))
    }
}

output JSON is:

[
  {
    "name": "dad",
    "kids": [
      {
        "name": "kid1"
      },
      {
        "name": "kid2",
        "kids": [
          {
            "name": "grandkid1"
          },
          {
            "name": "grandkid2"
          }
        ]
      }
    ]
  },
  {
    "name": "store",
    "kids": [
      {
        "name": "duck1"
      },
      {
        "name": "duck2"
      }
    ]
  }
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM