Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] QML with nested Repeaters, created dynamically
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] QML with nested Repeaters, created dynamically

Scheduled Pinned Locked Moved General and Desktop
2 Posts 1 Posters 1.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    jflatt
    wrote on last edited by
    #1

    I am trying to use QML to create some reports driven by an xml data file, which looks like this:
    @<xml>
    <Customer name="Fred">
    <Invoice date="1/1/2015" status="Paid">
    <Product category="Shirt" price="10"/>
    <Product category="Pants" price="20"/>
    </Invoice>
    <Invoice date="1/2/2015" status="Pending">
    <Product category="Socks" price="5"/>
    <Product category="Pants" price="15"/>
    </Invoice>
    </Customer>
    </xml>
    @

    The resulting report should effectively use something like this:
    @import QtQuick 2.1
    import QtQuick.XmlListModel 2.0

    Column {
    Repeater {
    model: XmlListModel {
    id: model1
    source: "data.xml"
    query: "/xml/Customer"
    XmlRole { name: "name"; query: "@name/string()" }
    }
    delegate: Column {
    Text { text: name; color: "orange" }
    Repeater {
    model: XmlListModel {
    id: model2
    source: model1.source
    query: model1.query + "[" + (index + 1) + "]" + "/Invoice"
    XmlRole { name: "date"; query: "@date/string()" }
    XmlRole { name: "status"; query: "@status/string()" }
    }
    delegate: Column {
    Row {
    Text { text: date; color: "red" }
    Text { text: " - " + status; color: "green" }
    }
    Repeater {
    model: XmlListModel {
    id: model3
    source: model2.source
    query: model2.query + "[" + (index + 1) + "]" + "/Product"
    XmlRole { name: "name"; query: "@category/string()" }
    XmlRole { name: "price"; query: "@price/number()" }
    }
    delegate: Column {
    Row {
    Text { text: name }
    Text { text: " = $" + price; color: "purple" }
    }
    }
    }
    }
    }
    }
    }
    }
    @

    This example QML document uses three nested repeaters to dig into the hierarchical xml data and produce the expected output. To take it a step further, I'd like to be able to use a different order in the xml data. Whereas this example is Customer/Invoice/Product, I'd like to be able to reorder it into Product/Invoice, with different orders of elements and different counts of elements. The xml source data would be rearranged to fit the expected report output, of course. Eventually it should handle any number of elements without limits.

    What I've tried to do is use QQuickItem::findChild(), but soon realized I can't get a handle into the Repeater delegates to be able to rearrange them.

    I was able to break each repeater into a separate file, and do something like this successfully:
    @view->setSource(QUrl("qrc:/reportbase.qml"));
    QQuickItem* item = view->rootObject();
    item->setProperty("source", fileName);

    //first iteration
    QQmlEngine* engine = view->engine();
    QQuickItem* col = item->findChild<QQuickItem*>("outerColumn");
    QQmlContext* context = engine->contextForObject(col);
    QQmlComponent component(engine, QUrl("qrc:/reportfragment.qml"));
    QQuickItem* object = qobject_cast<QQuickItem*>(component.create(context));
    object->setParentItem(col);

    QObject* model = object->findChild<QObject*>("xmlListModel");
    model->setProperty("source", fileName);
    model->setProperty("query", "/xml/Customer");

    QObject* role = model->findChild<QObject*>("roleName");
    role->setProperty("query", "@name/string()");

    //second iteration
    QQmlContext* context2 = engine->contextForObject(object);
    QQmlComponent component2(engine, QUrl("qrc:/reportfragment.qml"));
    QQuickItem* object2 = qobject_cast<QQuickItem*>(component2.create(context2));
    object2->setParentItem(object);
    @

    But produced a column of repeaters without the nesting. Has anybody done something similar to this? Or am I going about it all wrong?

    1 Reply Last reply
    0
    • J Offline
      J Offline
      jflatt
      wrote on last edited by
      #2

      I ended up passing a path string from the c++ side that looks like "/xml/Customer/Order/Product", parsing that in the QML side via JavaScript, and used the Qt.createQmlObject() method to do the nesting. It's not as ugly as I thought it might be, and I agree that it is nice keeping the display code contained in the QML side of things.

      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved