Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-114194

"Connecting signals to methods and signals" documentation should mention lifetime of connections

    XMLWordPrintable

Details

    Description

      https://doc.qt.io/qt-6/qtqml-syntax-signals.html#connecting-signals-to-methods-and-signals mentions how to connect and disconnect from a signal, but it doesn't mention the lifetime of those connections. Under normal (C++) connections rules, if a sender or receiver is destroyed, the connection is destroyed along with it. The rules for QML/JavaScript, however, are not clear:

      import QtQuick
      import QtQuick.Controls
      
      ApplicationWindow {
          id: root
          width: 400
          height: 400
          visible: true
      
          CheckBox {
              id: loadedCheckBox
              text: "Load some UI that listens to\n the position of rect while it's loaded"
              width: parent.width
          }
      
          Rectangle {
              id: rect
              y: 100
              width: 32
              height: 32
              color: "tomato"
          }
      
          NumberAnimation {
              target: rect
              property: "x"
              duration: 2000
              from: 0
              to: root.width - rect.width
              easing.type: Easing.InOutQuad
              loops: Animation.Infinite
              running: true
          }
      
          Loader {
              active: loadedCheckBox.checked
              sourceComponent: Item {
                  Component.onCompleted: {
                      // In the real-world example, it's also not possible to reference rect via id.
                      let imperativeReferenceToRect = rect
                      imperativeReferenceToRect.xChanged.connect(() => {
                          print("rect.x changed:", imperativeReferenceToRect.x)
                      })
                  }
              }
          }
      }
      

      In this example I want the connection to "rect" to only be alive as long as the UI it was created in is alive. However, that doesn't work, as the callback is kept alive even after the Loader it was created unloads its item.

      To reproduce, check the check box. Output will be printed as long as it's checked. Now uncheck it - the output should stop being printed, but it's not.

      For it to work, the disconnect must be done explicitly:

      import QtQuick
      import QtQuick.Controls
      
      ApplicationWindow {
          id: root
          width: 400
          height: 400
          visible: true
      
          CheckBox {
              id: loadedCheckBox
              text: "Load some UI that listens to\n the position of rect while it's loaded"
              width: parent.width
          }
      
          Rectangle {
              id: rect
              y: 100
              width: 32
              height: 32
              color: "tomato"
          }
      
          NumberAnimation {
              target: rect
              property: "x"
              duration: 2000
              from: 0
              to: root.width - rect.width
              easing.type: Easing.InOutQuad
              loops: Animation.Infinite
              running: true
          }
      
          Loader {
              active: loadedCheckBox.checked
              sourceComponent: Item {
                  function xUpdated() {
                      print("rect.x changed:", rect.x)
                  }
      
                  Component.onCompleted: rect.xChanged.connect(xUpdated)
                  Component.onDestruction: rect.xChanged.disconnect(xUpdated)
              }
          }
      }
      

      The rules surrounding this should be documented; it should be made clear that callbacks live beyond the components that they were created in (if this is actually intentional).

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              olivier.decanniere Olivier De Cannière
              mitch_curtis Mitch Curtis
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes