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

QML fails to bind to QObject property (defined with Q_OBJECT_BINDABLE_PROPERTY and BINDABLE) that are a type Q_GADGET

    XMLWordPrintable

Details

    • All
    • 44ca1085d (dev), c83dd11eb (6.5)

    Description

      If QObject has Q_PROPERTY that's a type of QGADGET, binding in QML don't work as expected. The QML bindings don't update when the value has change or initialize correctly. A work around is to remove  BINDABLE from the Q_PROPERTY, but isn't ideal because it looses the benefits of the binding. '

      I've attached a minimum example, that demonstrates the bug. 

      Here's a following example that doesn't work:

      import QtQuick
      import QtQuick.Window
      import doubleBinding 1.0
      Window {
          width: 640
          height: 480
          visible: true
          title: qsTr("Hello World")
          MouseArea {
              anchors.fill: parent
              onClicked: {
                  console.log("clicked")
                  var time = aId.x.timeIndex + 1
                  aId.x = WeatherModelUrlUtils.url(time); //This assignment works
              }
          }
          A {
              id: aId
              x: WeatherModelUrlUtils.url(1); //This binding doesn't work
              onXChanged: {
                  console.log("x changed:" + aId.x.timeIndex)
              }
          }
          B {
              id: bId
              y: aId.x //This binding doesn't work
              onZChanged: {
                  console.log("z changed:" + bId.z)
              }
          }
          Text {
              text: "aId.x.timeIndex:" + aId.x.timeIndex + "\nbId.y.timeIndex:" + bId.y.timeIndex + "\nb.z:" + bId.z
          }
          Text {
              anchors.centerIn: parent
              text: "Click to change the time index"
              font.pixelSize: 20
          }
      }
       
      

      The c++ code for A and B:

      #ifndef A_H
      #define A_H
      #include <QObject>
      #include <QProperty>
      #include <QtQml>
      //Our includes
      #include "WeatherModelUrl.h"
       
      class A : public QObject
      {
          Q_OBJECT
          QML_ELEMENT
          //This doesn't work.
          Q_PROPERTY(WeatherModelUrl x READ x WRITE setX NOTIFY xChanged BINDABLE bindableX)
          //This works
      //    Q_PROPERTY(WeatherModelUrl x READ x WRITE setX NOTIFY xChanged)
      
              public:
                       explicit A(QObject *parent = nullptr) : QObject(parent) {}
          WeatherModelUrl x() const { return m_x.value(); }
          void setX(const WeatherModelUrl& newX) { m_x.setValue(newX);}
          QBindable<WeatherModelUrl> bindableX() { return QBindable<WeatherModelUrl>(&m_x); }
      signals:
          void xChanged();
      private:
          Q_OBJECT_BINDABLE_PROPERTY(A, WeatherModelUrl, m_x, &A::xChanged)
      };
      class B : public QObject
      {
          Q_OBJECT
          QML_ELEMENT
          //This doesn't work.
          Q_PROPERTY(WeatherModelUrl y READ y WRITE setY NOTIFY yChanged BINDABLE bindableY)
          //This works!
      //    Q_PROPERTY(WeatherModelUrl y READ y WRITE setY NOTIFY yChanged)
          Q_PROPERTY(int z READ z NOTIFY zChanged)
      public:
          explicit B(QObject *parent = nullptr) : QObject(parent) {
              m_z.setBinding([this]()->int {
                  auto y = m_y.value();
                  if(y.timeIndex() < 2) {
                      return -1;
                  }
                  return y.timeIndex() * 2;
              });
          }
          WeatherModelUrl y() const { return m_y.value(); }
          void setY(const WeatherModelUrl& newY) { m_y.setValue(newY); }
          QBindable<WeatherModelUrl> bindableY() { return QBindable<WeatherModelUrl>(&m_y); }
          int z() const { return m_z.value(); }
          QBindable<int> bindableZ() const { return QBindable<int>(&m_z); }
      signals:
          void yChanged();
          void zChanged();
      private:
          Q_OBJECT_BINDABLE_PROPERTY(B, WeatherModelUrl, m_y, &B::yChanged)
          Q_OBJECT_BINDABLE_PROPERTY(B, int, m_z, &B::zChanged)
      };
      #endif // A_H
      

       

      The WeatherModelUrl Q_GADGET:

      #ifndef WEATHERMODELURL_H
      #define WEATHERMODELURL_H
      #include <QtQml>
      #include <QObject>
      //#include "Result.h"
      class WeatherModelUrl
      {
          Q_GADGET
              QML_NAMED_ELEMENT(weatherModelUrl)
          QML_UNCREATABLE("WeatherModelUrl is uncreatable");
          Q_PROPERTY(qsizetype timeIndex READ timeIndex CONSTANT)
      public:
          WeatherModelUrl() :
              m_timeIndex(-1)
             {}
             WeatherModelUrl(qsizetype timeIdx) :
                 m_timeIndex(timeIdx)
             {}
          // Getters
          qsizetype timeIndex() const { return m_timeIndex; }
          bool operator ==(const WeatherModelUrl &other) const;
          bool operator !=(const WeatherModelUrl &other) const;
      private:
          qsizetype m_timeIndex;
      };
      QML_DECLARE_TYPE(WeatherModelUrl)
      QDebug operator<<(QDebug debug, const WeatherModelUrl &url);
      ////For QML use
      class WeatherModelUrlUtils : public QObject
      {
          Q_OBJECT
          QML_ELEMENT
          QML_SINGLETON
          public:
          WeatherModelUrlUtils(QObject* parent = nullptr) : QObject(parent) {}
          Q_INVOKABLE static WeatherModelUrl url(int timeIdx) {
             return WeatherModelUrl(timeIdx);
          }
      };
      #endif // WEATHERMODELURL_H
      

       

      Attachments

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

        Activity

          People

            ulherman Ulf Hermann
            vpicaver Philip Schuchardt
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes