Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML syntax for QVariantMaps?
Forum Update on Monday, May 27th 2025

QML syntax for QVariantMaps?

Scheduled Pinned Locked Moved QML and Qt Quick
7 Posts 2 Posters 14.2k Views
  • 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.
  • M Offline
    M Offline
    mjmvisser
    wrote on last edited by
    #1

    I'm using QML as a general scene language for a node-graph type of project I'm doing. This syntax works OK:

    @
    Scene {
    contents: [
    SomeNode {
    name: "node1"
    values: [
    Value {
    name: "v1"
    value: 1
    },
    Value {
    name: "v2"
    value: 2
    }
    ]
    }
    ]
    }
    @

    Where Scene.qml defines the "contents" property (as list), and SomeNode.qml defines the "name" (string) and "values" (list<Value>) property.

    What I really want is that "contents" and "values" be of type map<Value> (which obviously doesn't exist in QML). They would then be available in Javascript as an Object, and in C++ as a QVariantMap. In QML, it might look like this:

    @
    Scene {
    contents: {
    "node1": SomeNode {
    values: {
    "v1": Value {
    name: "v1"
    value: 1
    },
    "v2": Value {
    name: "v2"
    value: 2
    }
    }
    }
    }
    }
    @

    This seems like a natural and useful extension to QML. Or am I smoking crack? :-)

    cheers,
    -Mark

    1 Reply Last reply
    0
    • C Offline
      C Offline
      chriadam
      wrote on last edited by
      #2

      JavaScript objects are converted to QVariantMaps when assigned to variant properties.
      That is, if you have:
      @
      Item {
      property variant myMap: { "v1": { "name": "v1", "value": 1 }, "v2" : {"name": "v2", "value": 2} } // or whatever
      }
      @
      And then you access that property from C++ via QObject::property(), it will be a QVariantMap.

      The problem (I believe) is that you've defined contents and values as a list property (I believe), and hence you are assigning those properties array values.

      Or have I misunderstood your question?

      Cheers,
      Chris.

      [Wrapped code in @ tags; mlong]

      1 Reply Last reply
      0
      • M Offline
        M Offline
        mjmvisser
        wrote on last edited by
        #3

        Sorta. The difference is that in your example, myMap can only contain basic types, not QObject-derived types. Also, changing a value inside myMap won't generate a notification signal.

        I thought about it some more, and my conclusion is that I'll need to think about it some more. :-) QtQuick is a weird and wonderful blend of static and dynamic-ness, and I'm still trying to wrap my head around it.

        cheers,
        -Mark

        1 Reply Last reply
        0
        • C Offline
          C Offline
          chriadam
          wrote on last edited by
          #4

          Ah, I see.

          Yeah, in QtQuick 2 a lot of those problems were solved with the addition of "var" properties (which store JS references). You can store basically anything in them (references to JS arrays, functions, objects, qobject-derived instance references, etc). But, they still don't notify if one of the values changes - we had an implementation which allowed construction of a "bindable/notifying" js object, but in practice its performance was so bad that we decided against including it. The plan is to add support for it in the future (there is a task on the public bugtracker about bindable js objects) but no ETA on when it'll be complete.

          Cheers,
          Chris.

          1 Reply Last reply
          0
          • M Offline
            M Offline
            mjmvisser
            wrote on last edited by
            #5

            Well, here's what I'm trying to do. Maybe there's an idiomatic approach that I'm missing?

            There are Nodes and Params. Nodes do things, like raise a number to a power, or compute the BRDF of a surface. Params define the inputs and outputs of Nodes, and have associated metadata for use by the UI presenting them.

            For example, say an Pow raises "base" to "expo":

            @
            // Pow.qml
            import QtQuick 1.1

            Node {
            label: "Power"

            params: [
                Param {
                    id: baseParam
                    name: "base"
                    label: "Base"
                },
                Param {
                    id: expoParam
                    name: "expo"
                    label: "Exponent"
                },
                Result {
                    id: result
                    name: "result"
                    display: "hidden"
                }
            ]
            property alias base: baseParam.value
            property alias expo: expoParam.value
            property alias result: resultParam.value
            

            }
            @

            One would then instantiate a Pow object like so:

            @
            Pow {
            base: 10
            expo: 2
            }
            @

            (I'm ignoring the actual computation of result for now. Insert hand-waving.)

            Querying the "result" property would give you 10^2. Pretty useless, but if you have multiple nodes, you can connect them together:

            @
            Pow {
            id: pow1
            base: 10
            expo: 2
            }
            Pow {
            id: pow2
            base: pow1.result
            expo: pow1.result
            }
            @

            A rather useless example, but you can see that pow2.result will magically evaluate (10^2)^(10^2).

            My problem is that I want Params to be somewhat dynamic, for example:

            @
            // Add.qml
            Node {
            label: "Add Numbers"

            params: [
                Repeater {
                    id: vParam
                    model: 1
                    Param {
                        name: "v" + index
                        label: "Value " + index
                    }
                },
                Param {
                    id: resultParam
                    name: result
                    display: "hidden"
                }
            ]
            
            property alias count: vParam.model
            property alias v1: vParam.????
            property alias v2: vParam.????
            ...
            property alias vN: vParam.????
            property alias result: resultParam.value
            

            }
            @

            And after instantiation:

            @
            // ...

            Add {
            id: add1
            count: 3
            v1: someOtherNode.result
            v2: etc.result
            v3: 25
            }
            @

            This dynamism is a recurring motif in the project I'm planning, so I'm trying to find a good idiom to represent it using QML. I'm not ruling out writing my own QtDeclarative classes with custom parsers (a la ListElement) if that's what it takes. But even if that's necessary, I'd rather build on top of best-practices than beat QML into submission with a hammer. :-)

            1 Reply Last reply
            0
            • C Offline
              C Offline
              chriadam
              wrote on last edited by
              #6

              I spoke to Michael Brasser about this briefly today. I'm not sure if I fully understood what you're trying to achieve, but basically I came up with the following:

              @
              // Add.qml - provides the "Add" node implementation
              import QtQuick 2.0
              Item {
              id: addElement

              // all node types must have the following three properties
              property bool isANode: true
              property var inputs
              property var result
              
              // this function will be the same for all node/operation types.
              onInputsChanged: {
                  // disconnect all current connections.
                  onAnyInputResultChanged.disconnectEverything(); // not sure what the "actual" api is to do this...
              
                  // create new connections.
                  for (var i = 0; i &lt; inputs.length; ++i) {
                      var currInput = inputs[i];
                      if (currInput.isObject()) {
                          if (currInput.isANode) {
                              currInput.onResultChanged.connect(inputResultChanged);
                          }
                      }
                  }
              
                  // update result.
                  inputResultChanged();
              }
              
              // this function will be different for each node/operation type.
              // the Add node simply adds up the various inputs' results / values,
              // and exposes the result via its result property.
              function inputResultChanged() {
                  var tmp = 0;
                  for (var i = 0; i &lt; inputs.length; ++i) {
                      var currInput = inputs[i];
                      if (currInput.isObject()) {
                          if (currInput.isANode) {
                              tmp += currInput.result.valueOf(); // grab the node's result as a number.
                          } else {
                              tmp += currInput.valueOf(); // convert random object to number.
                          }
                      } else {
                          tmp += currInput; // must be a number or primitive already.
                      }
                  }
              
                  result = tmp; // will cause notify signal to be emitted.
              }
              

              }
              @

              That way, at run-time, you can dynamically create Add nodes, and modify the input nodes as required. When the input nodes change, or when the result property of any input nodes change, the result of the node will be automatically updated.

              The one "tricky" bit is the "disconnect all current connects to the auto-update function on change" (prior to rebuilding it) -- I'm not sure what the API is for that, but I'm fairly certain it's possible (there's a notify list or signal connection list there somewhere, which can be updated).

              Cheers,
              Chris.

              1 Reply Last reply
              0
              • M Offline
                M Offline
                mjmvisser
                wrote on last edited by
                #7

                Thanks Chris. I haven't had a chance to build QtQuick 2.0 yet, but from your example, it looks like the new var type is exactly what I was looking for.

                cheers,
                -Mark

                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