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. How to bind a delegate item property to top-level property
Forum Updated to NodeBB v4.3 + New Features

How to bind a delegate item property to top-level property

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
13 Posts 5 Posters 1.8k 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
    jbrend
    wrote on last edited by jbrend
    #1

    Would it be possible to provide an example of how to bind a property in a delegate item to a top-level property using the recommended method as of Qt 6.3.0 (beta3)?

    The following example is contrived, but illustrates how I was shown in the past how to implement this sort of thing.

    Here, I want the text value of each of the delegate Text items to update every time the top-level property root.num is updated.

    main.qml

    import QtQuick
    import QtQuick.Controls
    
    Rectangle {
        id: root
        width: 400
        height: 200
        color: "beige"
    
        property int num: 0
    
        Row {
            id: row
            spacing: 10
            anchors.centerIn: parent
    
            Repeater {
                id: rpt
                model: 5
    
                delegate: Text {
                    id: txt
                    text: root.num.toString()
                }
            }
        }
    
        Button {
            id: btn
            anchors.bottom: root.bottom
            anchors.horizontalCenter: root.horizontalCenter
            text: "Click!"
            onClicked: {
                console.log( root.num )
                root.num += 2
            }
        }
    }
    

    But when I run qmllint on it, I get these diagnostic messages:

    $ qmllint --compiler warning main.qml
    Warning: main.qml:23:11: Unqualified access
                                    text: root.num.toString()
                                    ^^^^
    Warning: main.qml:23:11: Could not compile binding for text: Cannot access value for name root
                                    text: root.num.toString()
                                    ^^^^
    
    

    Outside of that, the code seems to work just fine.

    I am using Qt 6.3.0 beta3 on Kubuntu Linux 21.10.

    Thanks very much in advance!

    1 Reply Last reply
    0
    • B Offline
      B Offline
      Bob64
      wrote on last edited by
      #2

      I can't see anything wrong with this. It works for me in 5.15.

      Perhaps a bug, given that you are using a beta version?

      1 Reply Last reply
      0
      • J Offline
        J Offline
        jbrend
        wrote on last edited by
        #3

        The issues qmllint has caught are very valid and result from referencing an outer-level variable that could be (though not in this case) defined in another file. As I understand it, Qt recommends against this given the potential for runtime type mismatches that may be external in nature. This would also prevent the QML compiler from compiling such code.

        In many cases, this problem can be alleviated using a chain of required properties. However, I can find no way of "tunnelling" a property binding through a delegate using that approach.

        1 Reply Last reply
        0
        • B Offline
          B Offline
          Bob64
          wrote on last edited by
          #4

          OK, sorry, it looks like I did not read your original message carefully enough. Nevertheless, I still don 't see why this is a problem. root seems pretty unambiguous in the scope hierarchy.

          J.HilkJ 1 Reply Last reply
          0
          • B Bob64

            OK, sorry, it looks like I did not read your original message carefully enough. Nevertheless, I still don 't see why this is a problem. root seems pretty unambiguous in the scope hierarchy.

            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #5

            @Bob64 said in How to bind a delegate item property to top-level property:

            OK, sorry, it looks like I did not read your original message carefully enough. Nevertheless, I still don 't see why this is a problem. root seems pretty unambiguous in the scope hierarchy.

            technically yes, but if the shown file would not have an Element with the id:root, qml actually traverses the the parents/child tree upwards, until your very own main.qml file or until it finds an item with the id:root

            I ran into this, very hard and confusing to debug.


            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            B 1 Reply Last reply
            0
            • J.HilkJ J.Hilk

              @Bob64 said in How to bind a delegate item property to top-level property:

              OK, sorry, it looks like I did not read your original message carefully enough. Nevertheless, I still don 't see why this is a problem. root seems pretty unambiguous in the scope hierarchy.

              technically yes, but if the shown file would not have an Element with the id:root, qml actually traverses the the parents/child tree upwards, until your very own main.qml file or until it finds an item with the id:root

              I ran into this, very hard and confusing to debug.

              B Offline
              B Offline
              Bob64
              wrote on last edited by
              #6

              @J-Hilk I feel that I am still missing something.

              "... if the shown file would not have an Element with the id:root ..."

              Yes, I can understand why a warning would be shown in that case, but in this case it does have an element with id root, so why warn about it? Does qmllint not take any account of the context?

              1 Reply Last reply
              0
              • S Offline
                S Offline
                supa5000
                wrote on last edited by supa5000
                #7

                In at least my case i get rid of the warning with kind of nonsense declaration:

                            delegate: Text {
                                id: txt
                                readonly property var root: root
                                text: root.num.toString()
                            }
                
                

                EDIT: BUT BEWARE! As @jbrend wrote later - and i noticed later - this does not work in real application; the qmllint is happy but the real application does not work! Is no solution!

                J 1 Reply Last reply
                0
                • S supa5000

                  In at least my case i get rid of the warning with kind of nonsense declaration:

                              delegate: Text {
                                  id: txt
                                  readonly property var root: root
                                  text: root.num.toString()
                              }
                  
                  

                  EDIT: BUT BEWARE! As @jbrend wrote later - and i noticed later - this does not work in real application; the qmllint is happy but the real application does not work! Is no solution!

                  J Offline
                  J Offline
                  jbrend
                  wrote on last edited by
                  #8

                  @supa5000 I tried your solution using Qt 6.3.0 (released), but I get the following qmllint warning:

                  $ qmllint --compiler warning main.qml
                  
                  Warning: main.qml:24:28: Could not compile binding for text: Cannot load property num from QVariant of ??::root with type QVariant.
                                  text: root.num.toString()
                                             ^^^
                  

                  If I just run the file using qml, I get the following output to the console. The app window shows, but the Text items are not visible.

                  $ qml main.qml
                  file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                  file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                  file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                  file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                  file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                  file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                  file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                  file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                  file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                  file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                  

                  If I use the type of the root item (Rectangle instead of var), I get a similar but expanded warning:

                  $ qmllint --compiler warning main.qml
                  Warning: main.qml:24:28: Property "num" not found on type "QQuickRectangle"
                                  text: root.num.toString()
                                             ^^^
                  Warning: main.qml:24:28: Could not compile binding for text: Cannot load property num from QQuickRectangle of ??::root with type QQuickRectangle.
                                  text: root.num.toString()
                                             ^^^
                  

                  The warning about QuickRectangle not having a num property makes sense, since my subclassed version derived from it has the property.

                  In order to create compilable QML, I think we are supposed to be getting away from relying on the old context-based resolution mechanisms and also away from using var (QVariant) as a type, but I don't know what we are supposed to be doing in such a case from within a delegate.

                  Does anyone have any updated information?

                  S 1 Reply Last reply
                  0
                  • J jbrend

                    @supa5000 I tried your solution using Qt 6.3.0 (released), but I get the following qmllint warning:

                    $ qmllint --compiler warning main.qml
                    
                    Warning: main.qml:24:28: Could not compile binding for text: Cannot load property num from QVariant of ??::root with type QVariant.
                                    text: root.num.toString()
                                               ^^^
                    

                    If I just run the file using qml, I get the following output to the console. The app window shows, but the Text items are not visible.

                    $ qml main.qml
                    file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                    file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                    file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                    file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                    file:///srv/tests/qt/TunnelProp/main.qml:21:23: QML QQuickText*: Binding loop detected for property "root"
                    file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                    file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                    file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                    file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                    file:///srv/tests/qt/TunnelProp/main.qml:24: TypeError: Cannot read property 'num' of undefined
                    

                    If I use the type of the root item (Rectangle instead of var), I get a similar but expanded warning:

                    $ qmllint --compiler warning main.qml
                    Warning: main.qml:24:28: Property "num" not found on type "QQuickRectangle"
                                    text: root.num.toString()
                                               ^^^
                    Warning: main.qml:24:28: Could not compile binding for text: Cannot load property num from QQuickRectangle of ??::root with type QQuickRectangle.
                                    text: root.num.toString()
                                               ^^^
                    

                    The warning about QuickRectangle not having a num property makes sense, since my subclassed version derived from it has the property.

                    In order to create compilable QML, I think we are supposed to be getting away from relying on the old context-based resolution mechanisms and also away from using var (QVariant) as a type, but I don't know what we are supposed to be doing in such a case from within a delegate.

                    Does anyone have any updated information?

                    S Offline
                    S Offline
                    supa5000
                    wrote on last edited by supa5000
                    #9

                    @jbrend My bad, you are right. It did pass qmllint and our test-cases - but indeed as you wrote, it does not work.

                    i will edit my old answear to include warning that dont do this.

                    No doing it like

                                    readonly property var rootLoop: root
                                    text: rootLoop.num.toString()
                    

                    makes the main application to work again, but guess what qmllint says: Unqualified access (on the 'root') part ..

                    S 1 Reply Last reply
                    0
                    • S supa5000

                      @jbrend My bad, you are right. It did pass qmllint and our test-cases - but indeed as you wrote, it does not work.

                      i will edit my old answear to include warning that dont do this.

                      No doing it like

                                      readonly property var rootLoop: root
                                      text: rootLoop.num.toString()
                      

                      makes the main application to work again, but guess what qmllint says: Unqualified access (on the 'root') part ..

                      S Offline
                      S Offline
                      supa5000
                      wrote on last edited by
                      #10

                      I am keeping monologue here but another way to fix this is by "injecting" the upper scope variables via modelData;

                          function packItems(namespace, dataArray) {
                              var ret = [];
                              for (var loop = 0; loop < dataArray.length; loop++) {
                                  ret.push([namespace, dataArray[loop]]);
                              }
                              return ret;
                          }
                      

                      And then inject:

                         Repeater:
                           model: packItems( {"root":root }, myDataArray ) 
                               delegate: Text {
                                      id: txt
                                      required property var modelData
                                      readonly property rootLoop: modelData[0]["root"]
                      

                      This is fishy at most, but works and passes the qml lint; i kind of feel like ill doing this; in my case i need the upper level component information for:

                      • delegate item calls root.signalEmitFunction -- when certain button of the delegate item is clicked
                      • delegete item width depends on upper level item width
                      • delegate item position depends on upper level item properties (slider tickmark labels position to be precise)
                      • delegate item gives focus to upper level when released (i guess focus-manager or whatever could do this also)
                      J 1 Reply Last reply
                      0
                      • GrecKoG Offline
                        GrecKoG Offline
                        GrecKo
                        Qt Champions 2018
                        wrote on last edited by GrecKo
                        #11

                        Your packItems could be written like that instead: return dataArray.map(data => {data: data, namespace: namespace});

                        and used like so : readonly property QtObject rootLoop: modelData.namespace.root

                        J 1 Reply Last reply
                        0
                        • S supa5000

                          I am keeping monologue here but another way to fix this is by "injecting" the upper scope variables via modelData;

                              function packItems(namespace, dataArray) {
                                  var ret = [];
                                  for (var loop = 0; loop < dataArray.length; loop++) {
                                      ret.push([namespace, dataArray[loop]]);
                                  }
                                  return ret;
                              }
                          

                          And then inject:

                             Repeater:
                               model: packItems( {"root":root }, myDataArray ) 
                                   delegate: Text {
                                          id: txt
                                          required property var modelData
                                          readonly property rootLoop: modelData[0]["root"]
                          

                          This is fishy at most, but works and passes the qml lint; i kind of feel like ill doing this; in my case i need the upper level component information for:

                          • delegate item calls root.signalEmitFunction -- when certain button of the delegate item is clicked
                          • delegete item width depends on upper level item width
                          • delegate item position depends on upper level item properties (slider tickmark labels position to be precise)
                          • delegate item gives focus to upper level when released (i guess focus-manager or whatever could do this also)
                          J Offline
                          J Offline
                          jbrend
                          wrote on last edited by
                          #12

                          @supa5000 Great idea and thanks for sharing it!

                          I'm going to leave this item open for now in case there might be more ideas on how to solve this problem.

                          1 Reply Last reply
                          0
                          • GrecKoG GrecKo

                            Your packItems could be written like that instead: return dataArray.map(data => {data: data, namespace: namespace});

                            and used like so : readonly property QtObject rootLoop: modelData.namespace.root

                            J Offline
                            J Offline
                            jbrend
                            wrote on last edited by
                            #13

                            @GrecKo Thank you for this syntax suggestion!

                            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