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

QProperty: Produce warning when a binding/evaluation loop is detected

    XMLWordPrintable

Details

    Description

      QML prints "Binding loop detected for property XYZ". Having a similar (toggleable?) warning in C++ could help to flag programming errors.

      (Demos below ran on Qt 6.4.2)

       

      QML code

      import QtQuick
      import QtQuick.Controls
      
      Window {
          visible: true
          width: 640
          height: 480
          property int alpha: 0
          property int beta: alpha
      
          onAlphaChanged: {
              if (alpha > 0) {
                  console.log("Going negative")
                  alpha = -1
              }
              console.log(`Alpha = ${alpha}    Beta = ${beta}`)
          }
          onBetaChanged: {
              if (alpha < 0) {
                  console.log("Going positive")
                  alpha = 1 // OR: `Qt.callLater(()=>{alpha = 1})` to remove Binding loop complaint
              }
              console.log(`Alpha = ${alpha}    Beta = ${beta}`)
          }
      
          Button {
              text: "Click Me"
              onClicked: alpha = 1
          }
      }
      
      

       

      C+ code+

      #include <QApplication>
      #include <QPushButton>
      #include <QProperty>
      #include <QDebug>
      
      int main(int argc, char *argv[])
      {
          qputenv("QT_LOGGING_RULES", "qt.qproperty.binding=true;");
      
          QApplication app(argc, argv);
      
          QProperty<int> alpha{0};
          QProperty<int> beta([&]{
              return alpha.value();
          });
      
          auto alphaHandler = alpha.onValueChanged([&]{
              if (alpha > 0)
              {
                  qDebug("Going negative");
                  alpha = -1;
              }
              qDebug().noquote() << u"Alpha = %1\tBeta = %2"_qs.arg(alpha).arg(beta);
          });
          auto betaHandler = beta.onValueChanged([&]{
              if (alpha < 0)
              {
                  qDebug("Going positive");
                  alpha = 1; // OR: `QTimer::singleShot(0, &app, [&]{alpha = 1;});` for infinite spam
              }
              qDebug().noquote() << u"Alpha = %1\tBeta = %2"_qs.arg(alpha).arg(beta);
          });
      
          QPushButton button("Click Me");
          QObject::connect(&button, &QPushButton::clicked, [&]{
              alpha = 1;
          });
          button.show();
      
          return app.exec();
      }
      
      

       

      QML output when button is clicked

      qml: Going negative
      qml: Alpha = -1    Beta = 0
      qml: Going positive
      qml: Going negative
      qml: Alpha = -1    Beta = -1
      qrc:/main.qml:4:1: QML QQuickWindowQmlImpl*: Binding loop detected for property "beta"
      qml: Alpha = -1    Beta = -1
      qrc:/main.qml:4:1: QML QQuickWindowQmlImpl*: Binding loop detected for property "beta"
      qml: Alpha = -1    Beta = -1
      qml: Alpha = -1    Beta = -1
      

       

      C+ output when button is clicked+

      Going negative
      Going positive
      Alpha = 1    Beta = -1
      Alpha = 1    Beta = -1
      

       

      Other observations

      • It looks like QProperty and the QML engine don't follow the same sequence when evaluating property bindings – is this intentional?
      • Both QProperty and the QML engine do have a mechanism to detect and break binding loops.

      Attachments

        Issue Links

          Activity

            People

              fabiankosmale Fabian Kosmale
              skoh-qt Sze Howe Koh
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated: