QT/QML scripting and property binding approach

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I'm asking your help to understand it the following code does something that should really be avoided.



The application I'm currently working on is an embedded HMI for a process controller who shares its status on a serial line. The application will be designed in QT (Quick). Stability of the application is essential (items manufactured in series).



I tried to take advantage from embedded ECMAScript interpreter of QT Quick and property binding automation; so I asked him to:



  • load QML from files for UI on runtime;

  • instantiate properties only in QML scripts;

  • Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)

  • use explicit binding as described below;

  • open up a window that lists all the properties of the backend object and allows to set communication parameters, inspect and change properties on the fly, and save list of properties and related configuration on a sqlite database.

I sent to an external developer (I am running out of time and I need help) a minimal (working) QT project example; simplified extracts of the code are listed below. The requirements and the architecture have been heavily criticized by the developer (to the extent that if I want the software written that way I have to do it by myself). While I understand some of his concerns (property initialization drifts from default use case), I don't see anything inherently wrong with the suggested approach, so I kindly ask anyone of you who has experience with QT/QML to help me understand if and where the approach I was triyng to discuss is really flawing, since I am still not getting the point and I need to understand if I am that wrong.



QML window: driving properties are defined in QML within the "BackEnd". Notice that properties are defined within BackEnd object and automatically generated signals on<Property>Changed are connected to slots by connectProperties() once component has been loaded.



import com.mydomain.backend 1.0

Window
property BackEnd backEnd : BackEnd
property string property1 : "default property1 value"
property bool property2 : checkBox.checked


Column
Text
text: backEnd.property2

CheckBox
id: checkBox



Component.onCompleted:
backEnd.connectProperties()




C++ Backend. Callable connectProperties() function traverses MetaObject and connects methods from an object created on the fly



class BackEnd : public QObject

Q_OBJECT
public:
explicit BackEnd(QObject *parent = nullptr) : QObject(parent);
~BackEnd();
Q_INVOKABLE void connectProperties()

const QMetaObject *mo = this->metaObject();
for(int i = mo->propertyOffset(); i < mo->propertyCount(); ++i)

QMetaProperty property = mo->property(i);
auto po = new PropertySlot(this, property);
m_properties[property.name()] = po;
po->connectSlot();


private:
static QMap<QString, PropertySlot*> m_properties;
friend class PropertySlot;
;


And here is the glue class (here the connectSlot ensures connection between source event and related slot)



class PropertySlot : public QObject 
Q_OBJECT
public:
// Note: this is simplified, maybe the slot should be
// disconnected once destroyed event is reached.
void PropertySlot(const QObject *source, const QMetaProperty &property)

this.source = source;
this.name = property.name();
// Here QT does not allow to mix QMetaMethod with functors,
// so I ended up with PropertySlot class to circumvent the limitation.
QMetaObject *this_mo = PropertySlot::metaObject();
connect(source, property.notifySignal(), this,
this_mo->method(this_mo->indexOfSlot("propertyChanged()")));

public slots:
void propertyChanged()

// Send an event to a static function within I/O thread
// with property name and new value, ensure data is passed by copy.

private:
const QObject *source;
// Get by copy
QString name;
;


The properties updated by the I/O thread would be nearly 100 with a refresh rate between 1 to 10 seconds each. Updated properties from UI to I/O are user event based.



Those are the highlighted issues (maybe you could find other points that I missed)



  • Loading QML for windows at runtime is not the "best practice" and it would not add any practical benefit.

  • Explicit binding made by traversing MetaObject is "forcing the code", "bad practice" and leads to application flaws.

  • This code adds unnecessary event loop hops and it will slow down the embedded application

  • Invokables do not require to run the event loop; property update chain in response to user action might be perceived as application slowness

  • Added complexity (and potential issues) without benefit (no reason to do it this way)

  • Property inspection shall be performed by logging. A single window that lists all the properties encourages laziness in unit testing.

My points are:



  • QML is based on ECMAScript, and as such it is a scripting language. I don't see any difference (apart from the fact that a plain text file can be modified by the user, but that's what a scripting language is designed for) of loading the QML file from and URI located within the application binary and loading it from a local file.

  • The benefit of a scripting language is that it can be modified without recompilation; experiments can be performed on the device and it would ease development phase. Application is reconfigurable and it can be used in multiple future cases.

  • The risk of an unwanted change to text files in production is minimal on our embedded device; even in this case files might be signed to detect changes.

  • QML scripts are simple and they do not require recompilation, I can give it to a 'junior' developer and he could make adjustments with less efforts and see the results immediately, so that we can focus on glue logic instead of UI

  • Explicit binding avoids duplication of property declaration inside C++ classes, I/O thread and calls within QML. The code is reduced since a single slot is attached to each event generated when QML script is loaded. While the explicit binding is not endorsed by a large number of QT examples, the described approach uses standard functions and I don't see any potential break.

  • While working with control systems, it's very hard to set up unit testing from sequential phases without a phisical test hardware, and an overall view of variable values from within a single table would be of benefit. Logging does not give shapshot of status. UI might not show all the properties.

  • I see added complexity and risk in defining variable and properties in up to 4 different places: the QML code, the C++ backend, the I/O layer and the control board firmware. While the suggested approach adds some development efforts (and cost) the ability to reconfigure the application with reduced efforts would be a long term benefit.

The code above is tested in a simple use case and it works. Any comment is well appreciated.







share|improve this question

























    up vote
    2
    down vote

    favorite












    I'm asking your help to understand it the following code does something that should really be avoided.



    The application I'm currently working on is an embedded HMI for a process controller who shares its status on a serial line. The application will be designed in QT (Quick). Stability of the application is essential (items manufactured in series).



    I tried to take advantage from embedded ECMAScript interpreter of QT Quick and property binding automation; so I asked him to:



    • load QML from files for UI on runtime;

    • instantiate properties only in QML scripts;

    • Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)

    • use explicit binding as described below;

    • open up a window that lists all the properties of the backend object and allows to set communication parameters, inspect and change properties on the fly, and save list of properties and related configuration on a sqlite database.

    I sent to an external developer (I am running out of time and I need help) a minimal (working) QT project example; simplified extracts of the code are listed below. The requirements and the architecture have been heavily criticized by the developer (to the extent that if I want the software written that way I have to do it by myself). While I understand some of his concerns (property initialization drifts from default use case), I don't see anything inherently wrong with the suggested approach, so I kindly ask anyone of you who has experience with QT/QML to help me understand if and where the approach I was triyng to discuss is really flawing, since I am still not getting the point and I need to understand if I am that wrong.



    QML window: driving properties are defined in QML within the "BackEnd". Notice that properties are defined within BackEnd object and automatically generated signals on<Property>Changed are connected to slots by connectProperties() once component has been loaded.



    import com.mydomain.backend 1.0

    Window
    property BackEnd backEnd : BackEnd
    property string property1 : "default property1 value"
    property bool property2 : checkBox.checked


    Column
    Text
    text: backEnd.property2

    CheckBox
    id: checkBox



    Component.onCompleted:
    backEnd.connectProperties()




    C++ Backend. Callable connectProperties() function traverses MetaObject and connects methods from an object created on the fly



    class BackEnd : public QObject

    Q_OBJECT
    public:
    explicit BackEnd(QObject *parent = nullptr) : QObject(parent);
    ~BackEnd();
    Q_INVOKABLE void connectProperties()

    const QMetaObject *mo = this->metaObject();
    for(int i = mo->propertyOffset(); i < mo->propertyCount(); ++i)

    QMetaProperty property = mo->property(i);
    auto po = new PropertySlot(this, property);
    m_properties[property.name()] = po;
    po->connectSlot();


    private:
    static QMap<QString, PropertySlot*> m_properties;
    friend class PropertySlot;
    ;


    And here is the glue class (here the connectSlot ensures connection between source event and related slot)



    class PropertySlot : public QObject 
    Q_OBJECT
    public:
    // Note: this is simplified, maybe the slot should be
    // disconnected once destroyed event is reached.
    void PropertySlot(const QObject *source, const QMetaProperty &property)

    this.source = source;
    this.name = property.name();
    // Here QT does not allow to mix QMetaMethod with functors,
    // so I ended up with PropertySlot class to circumvent the limitation.
    QMetaObject *this_mo = PropertySlot::metaObject();
    connect(source, property.notifySignal(), this,
    this_mo->method(this_mo->indexOfSlot("propertyChanged()")));

    public slots:
    void propertyChanged()

    // Send an event to a static function within I/O thread
    // with property name and new value, ensure data is passed by copy.

    private:
    const QObject *source;
    // Get by copy
    QString name;
    ;


    The properties updated by the I/O thread would be nearly 100 with a refresh rate between 1 to 10 seconds each. Updated properties from UI to I/O are user event based.



    Those are the highlighted issues (maybe you could find other points that I missed)



    • Loading QML for windows at runtime is not the "best practice" and it would not add any practical benefit.

    • Explicit binding made by traversing MetaObject is "forcing the code", "bad practice" and leads to application flaws.

    • This code adds unnecessary event loop hops and it will slow down the embedded application

    • Invokables do not require to run the event loop; property update chain in response to user action might be perceived as application slowness

    • Added complexity (and potential issues) without benefit (no reason to do it this way)

    • Property inspection shall be performed by logging. A single window that lists all the properties encourages laziness in unit testing.

    My points are:



    • QML is based on ECMAScript, and as such it is a scripting language. I don't see any difference (apart from the fact that a plain text file can be modified by the user, but that's what a scripting language is designed for) of loading the QML file from and URI located within the application binary and loading it from a local file.

    • The benefit of a scripting language is that it can be modified without recompilation; experiments can be performed on the device and it would ease development phase. Application is reconfigurable and it can be used in multiple future cases.

    • The risk of an unwanted change to text files in production is minimal on our embedded device; even in this case files might be signed to detect changes.

    • QML scripts are simple and they do not require recompilation, I can give it to a 'junior' developer and he could make adjustments with less efforts and see the results immediately, so that we can focus on glue logic instead of UI

    • Explicit binding avoids duplication of property declaration inside C++ classes, I/O thread and calls within QML. The code is reduced since a single slot is attached to each event generated when QML script is loaded. While the explicit binding is not endorsed by a large number of QT examples, the described approach uses standard functions and I don't see any potential break.

    • While working with control systems, it's very hard to set up unit testing from sequential phases without a phisical test hardware, and an overall view of variable values from within a single table would be of benefit. Logging does not give shapshot of status. UI might not show all the properties.

    • I see added complexity and risk in defining variable and properties in up to 4 different places: the QML code, the C++ backend, the I/O layer and the control board firmware. While the suggested approach adds some development efforts (and cost) the ability to reconfigure the application with reduced efforts would be a long term benefit.

    The code above is tested in a simple use case and it works. Any comment is well appreciated.







    share|improve this question





















      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I'm asking your help to understand it the following code does something that should really be avoided.



      The application I'm currently working on is an embedded HMI for a process controller who shares its status on a serial line. The application will be designed in QT (Quick). Stability of the application is essential (items manufactured in series).



      I tried to take advantage from embedded ECMAScript interpreter of QT Quick and property binding automation; so I asked him to:



      • load QML from files for UI on runtime;

      • instantiate properties only in QML scripts;

      • Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)

      • use explicit binding as described below;

      • open up a window that lists all the properties of the backend object and allows to set communication parameters, inspect and change properties on the fly, and save list of properties and related configuration on a sqlite database.

      I sent to an external developer (I am running out of time and I need help) a minimal (working) QT project example; simplified extracts of the code are listed below. The requirements and the architecture have been heavily criticized by the developer (to the extent that if I want the software written that way I have to do it by myself). While I understand some of his concerns (property initialization drifts from default use case), I don't see anything inherently wrong with the suggested approach, so I kindly ask anyone of you who has experience with QT/QML to help me understand if and where the approach I was triyng to discuss is really flawing, since I am still not getting the point and I need to understand if I am that wrong.



      QML window: driving properties are defined in QML within the "BackEnd". Notice that properties are defined within BackEnd object and automatically generated signals on<Property>Changed are connected to slots by connectProperties() once component has been loaded.



      import com.mydomain.backend 1.0

      Window
      property BackEnd backEnd : BackEnd
      property string property1 : "default property1 value"
      property bool property2 : checkBox.checked


      Column
      Text
      text: backEnd.property2

      CheckBox
      id: checkBox



      Component.onCompleted:
      backEnd.connectProperties()




      C++ Backend. Callable connectProperties() function traverses MetaObject and connects methods from an object created on the fly



      class BackEnd : public QObject

      Q_OBJECT
      public:
      explicit BackEnd(QObject *parent = nullptr) : QObject(parent);
      ~BackEnd();
      Q_INVOKABLE void connectProperties()

      const QMetaObject *mo = this->metaObject();
      for(int i = mo->propertyOffset(); i < mo->propertyCount(); ++i)

      QMetaProperty property = mo->property(i);
      auto po = new PropertySlot(this, property);
      m_properties[property.name()] = po;
      po->connectSlot();


      private:
      static QMap<QString, PropertySlot*> m_properties;
      friend class PropertySlot;
      ;


      And here is the glue class (here the connectSlot ensures connection between source event and related slot)



      class PropertySlot : public QObject 
      Q_OBJECT
      public:
      // Note: this is simplified, maybe the slot should be
      // disconnected once destroyed event is reached.
      void PropertySlot(const QObject *source, const QMetaProperty &property)

      this.source = source;
      this.name = property.name();
      // Here QT does not allow to mix QMetaMethod with functors,
      // so I ended up with PropertySlot class to circumvent the limitation.
      QMetaObject *this_mo = PropertySlot::metaObject();
      connect(source, property.notifySignal(), this,
      this_mo->method(this_mo->indexOfSlot("propertyChanged()")));

      public slots:
      void propertyChanged()

      // Send an event to a static function within I/O thread
      // with property name and new value, ensure data is passed by copy.

      private:
      const QObject *source;
      // Get by copy
      QString name;
      ;


      The properties updated by the I/O thread would be nearly 100 with a refresh rate between 1 to 10 seconds each. Updated properties from UI to I/O are user event based.



      Those are the highlighted issues (maybe you could find other points that I missed)



      • Loading QML for windows at runtime is not the "best practice" and it would not add any practical benefit.

      • Explicit binding made by traversing MetaObject is "forcing the code", "bad practice" and leads to application flaws.

      • This code adds unnecessary event loop hops and it will slow down the embedded application

      • Invokables do not require to run the event loop; property update chain in response to user action might be perceived as application slowness

      • Added complexity (and potential issues) without benefit (no reason to do it this way)

      • Property inspection shall be performed by logging. A single window that lists all the properties encourages laziness in unit testing.

      My points are:



      • QML is based on ECMAScript, and as such it is a scripting language. I don't see any difference (apart from the fact that a plain text file can be modified by the user, but that's what a scripting language is designed for) of loading the QML file from and URI located within the application binary and loading it from a local file.

      • The benefit of a scripting language is that it can be modified without recompilation; experiments can be performed on the device and it would ease development phase. Application is reconfigurable and it can be used in multiple future cases.

      • The risk of an unwanted change to text files in production is minimal on our embedded device; even in this case files might be signed to detect changes.

      • QML scripts are simple and they do not require recompilation, I can give it to a 'junior' developer and he could make adjustments with less efforts and see the results immediately, so that we can focus on glue logic instead of UI

      • Explicit binding avoids duplication of property declaration inside C++ classes, I/O thread and calls within QML. The code is reduced since a single slot is attached to each event generated when QML script is loaded. While the explicit binding is not endorsed by a large number of QT examples, the described approach uses standard functions and I don't see any potential break.

      • While working with control systems, it's very hard to set up unit testing from sequential phases without a phisical test hardware, and an overall view of variable values from within a single table would be of benefit. Logging does not give shapshot of status. UI might not show all the properties.

      • I see added complexity and risk in defining variable and properties in up to 4 different places: the QML code, the C++ backend, the I/O layer and the control board firmware. While the suggested approach adds some development efforts (and cost) the ability to reconfigure the application with reduced efforts would be a long term benefit.

      The code above is tested in a simple use case and it works. Any comment is well appreciated.







      share|improve this question











      I'm asking your help to understand it the following code does something that should really be avoided.



      The application I'm currently working on is an embedded HMI for a process controller who shares its status on a serial line. The application will be designed in QT (Quick). Stability of the application is essential (items manufactured in series).



      I tried to take advantage from embedded ECMAScript interpreter of QT Quick and property binding automation; so I asked him to:



      • load QML from files for UI on runtime;

      • instantiate properties only in QML scripts;

      • Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)

      • use explicit binding as described below;

      • open up a window that lists all the properties of the backend object and allows to set communication parameters, inspect and change properties on the fly, and save list of properties and related configuration on a sqlite database.

      I sent to an external developer (I am running out of time and I need help) a minimal (working) QT project example; simplified extracts of the code are listed below. The requirements and the architecture have been heavily criticized by the developer (to the extent that if I want the software written that way I have to do it by myself). While I understand some of his concerns (property initialization drifts from default use case), I don't see anything inherently wrong with the suggested approach, so I kindly ask anyone of you who has experience with QT/QML to help me understand if and where the approach I was triyng to discuss is really flawing, since I am still not getting the point and I need to understand if I am that wrong.



      QML window: driving properties are defined in QML within the "BackEnd". Notice that properties are defined within BackEnd object and automatically generated signals on<Property>Changed are connected to slots by connectProperties() once component has been loaded.



      import com.mydomain.backend 1.0

      Window
      property BackEnd backEnd : BackEnd
      property string property1 : "default property1 value"
      property bool property2 : checkBox.checked


      Column
      Text
      text: backEnd.property2

      CheckBox
      id: checkBox



      Component.onCompleted:
      backEnd.connectProperties()




      C++ Backend. Callable connectProperties() function traverses MetaObject and connects methods from an object created on the fly



      class BackEnd : public QObject

      Q_OBJECT
      public:
      explicit BackEnd(QObject *parent = nullptr) : QObject(parent);
      ~BackEnd();
      Q_INVOKABLE void connectProperties()

      const QMetaObject *mo = this->metaObject();
      for(int i = mo->propertyOffset(); i < mo->propertyCount(); ++i)

      QMetaProperty property = mo->property(i);
      auto po = new PropertySlot(this, property);
      m_properties[property.name()] = po;
      po->connectSlot();


      private:
      static QMap<QString, PropertySlot*> m_properties;
      friend class PropertySlot;
      ;


      And here is the glue class (here the connectSlot ensures connection between source event and related slot)



      class PropertySlot : public QObject 
      Q_OBJECT
      public:
      // Note: this is simplified, maybe the slot should be
      // disconnected once destroyed event is reached.
      void PropertySlot(const QObject *source, const QMetaProperty &property)

      this.source = source;
      this.name = property.name();
      // Here QT does not allow to mix QMetaMethod with functors,
      // so I ended up with PropertySlot class to circumvent the limitation.
      QMetaObject *this_mo = PropertySlot::metaObject();
      connect(source, property.notifySignal(), this,
      this_mo->method(this_mo->indexOfSlot("propertyChanged()")));

      public slots:
      void propertyChanged()

      // Send an event to a static function within I/O thread
      // with property name and new value, ensure data is passed by copy.

      private:
      const QObject *source;
      // Get by copy
      QString name;
      ;


      The properties updated by the I/O thread would be nearly 100 with a refresh rate between 1 to 10 seconds each. Updated properties from UI to I/O are user event based.



      Those are the highlighted issues (maybe you could find other points that I missed)



      • Loading QML for windows at runtime is not the "best practice" and it would not add any practical benefit.

      • Explicit binding made by traversing MetaObject is "forcing the code", "bad practice" and leads to application flaws.

      • This code adds unnecessary event loop hops and it will slow down the embedded application

      • Invokables do not require to run the event loop; property update chain in response to user action might be perceived as application slowness

      • Added complexity (and potential issues) without benefit (no reason to do it this way)

      • Property inspection shall be performed by logging. A single window that lists all the properties encourages laziness in unit testing.

      My points are:



      • QML is based on ECMAScript, and as such it is a scripting language. I don't see any difference (apart from the fact that a plain text file can be modified by the user, but that's what a scripting language is designed for) of loading the QML file from and URI located within the application binary and loading it from a local file.

      • The benefit of a scripting language is that it can be modified without recompilation; experiments can be performed on the device and it would ease development phase. Application is reconfigurable and it can be used in multiple future cases.

      • The risk of an unwanted change to text files in production is minimal on our embedded device; even in this case files might be signed to detect changes.

      • QML scripts are simple and they do not require recompilation, I can give it to a 'junior' developer and he could make adjustments with less efforts and see the results immediately, so that we can focus on glue logic instead of UI

      • Explicit binding avoids duplication of property declaration inside C++ classes, I/O thread and calls within QML. The code is reduced since a single slot is attached to each event generated when QML script is loaded. While the explicit binding is not endorsed by a large number of QT examples, the described approach uses standard functions and I don't see any potential break.

      • While working with control systems, it's very hard to set up unit testing from sequential phases without a phisical test hardware, and an overall view of variable values from within a single table would be of benefit. Logging does not give shapshot of status. UI might not show all the properties.

      • I see added complexity and risk in defining variable and properties in up to 4 different places: the QML code, the C++ backend, the I/O layer and the control board firmware. While the suggested approach adds some development efforts (and cost) the ability to reconfigure the application with reduced efforts would be a long term benefit.

      The code above is tested in a simple use case and it works. Any comment is well appreciated.









      share|improve this question










      share|improve this question




      share|improve this question









      asked Jan 24 at 22:04









      Fab

      134




      134




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote



          accepted










          I've developed my first QML application some months ago, so I'm far from an expert in QML. Here are some of my thoughts:



          Loading a QML file from disk vs. embedding it



          Nothing wrong about either of those.



          Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)



          That's called two-way bindings. The can be fine, but often leads to weird problems. If you only have a dumb value-store, it should be fine. Read this:



          https://stackoverflow.com/questions/28250710/qt-5-4-qml-prevent-binding-loop



           Architecture



          Here's how I implemented my application (sorry for any bugs, I don't have the source code here):



          QML:



          CheckBox 
          checked: Settings.everythingOk
          onCheckedChanged: Settings.everythingOk = checked



          C++ (not sure about the syntax)



          class Settings: public QObject 
          Q_OBJECT
          Q_PROPERTY(bool everythingOk MEMBER m_everythingOk NOTIFY everythingOkChanged)

          signals:
          void everythingOkChanged();

          private:
          bool m_everythingOk = false;



          and then I exposed Settings as a global singleton to QML. (It's also possible to expose it as a normal object if multiple instances are required.)



          To me this seems much simpler.



          Yes, it's slightly more to write, but not much. Your trick is clever, but it's not as future-proof as using a more standard approach.






          share|improve this answer























          • Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
            – Fab
            Jan 26 at 15:53











          • @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
            – Georg Schölly
            Jan 26 at 19:37










          • Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
            – Fab
            Jan 27 at 20:01











          • @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
            – Georg Schölly
            Feb 1 at 8:27










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185910%2fqt-qml-scripting-and-property-binding-approach%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote



          accepted










          I've developed my first QML application some months ago, so I'm far from an expert in QML. Here are some of my thoughts:



          Loading a QML file from disk vs. embedding it



          Nothing wrong about either of those.



          Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)



          That's called two-way bindings. The can be fine, but often leads to weird problems. If you only have a dumb value-store, it should be fine. Read this:



          https://stackoverflow.com/questions/28250710/qt-5-4-qml-prevent-binding-loop



           Architecture



          Here's how I implemented my application (sorry for any bugs, I don't have the source code here):



          QML:



          CheckBox 
          checked: Settings.everythingOk
          onCheckedChanged: Settings.everythingOk = checked



          C++ (not sure about the syntax)



          class Settings: public QObject 
          Q_OBJECT
          Q_PROPERTY(bool everythingOk MEMBER m_everythingOk NOTIFY everythingOkChanged)

          signals:
          void everythingOkChanged();

          private:
          bool m_everythingOk = false;



          and then I exposed Settings as a global singleton to QML. (It's also possible to expose it as a normal object if multiple instances are required.)



          To me this seems much simpler.



          Yes, it's slightly more to write, but not much. Your trick is clever, but it's not as future-proof as using a more standard approach.






          share|improve this answer























          • Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
            – Fab
            Jan 26 at 15:53











          • @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
            – Georg Schölly
            Jan 26 at 19:37










          • Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
            – Fab
            Jan 27 at 20:01











          • @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
            – Georg Schölly
            Feb 1 at 8:27














          up vote
          0
          down vote



          accepted










          I've developed my first QML application some months ago, so I'm far from an expert in QML. Here are some of my thoughts:



          Loading a QML file from disk vs. embedding it



          Nothing wrong about either of those.



          Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)



          That's called two-way bindings. The can be fine, but often leads to weird problems. If you only have a dumb value-store, it should be fine. Read this:



          https://stackoverflow.com/questions/28250710/qt-5-4-qml-prevent-binding-loop



           Architecture



          Here's how I implemented my application (sorry for any bugs, I don't have the source code here):



          QML:



          CheckBox 
          checked: Settings.everythingOk
          onCheckedChanged: Settings.everythingOk = checked



          C++ (not sure about the syntax)



          class Settings: public QObject 
          Q_OBJECT
          Q_PROPERTY(bool everythingOk MEMBER m_everythingOk NOTIFY everythingOkChanged)

          signals:
          void everythingOkChanged();

          private:
          bool m_everythingOk = false;



          and then I exposed Settings as a global singleton to QML. (It's also possible to expose it as a normal object if multiple instances are required.)



          To me this seems much simpler.



          Yes, it's slightly more to write, but not much. Your trick is clever, but it's not as future-proof as using a more standard approach.






          share|improve this answer























          • Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
            – Fab
            Jan 26 at 15:53











          • @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
            – Georg Schölly
            Jan 26 at 19:37










          • Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
            – Fab
            Jan 27 at 20:01











          • @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
            – Georg Schölly
            Feb 1 at 8:27












          up vote
          0
          down vote



          accepted







          up vote
          0
          down vote



          accepted






          I've developed my first QML application some months ago, so I'm far from an expert in QML. Here are some of my thoughts:



          Loading a QML file from disk vs. embedding it



          Nothing wrong about either of those.



          Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)



          That's called two-way bindings. The can be fine, but often leads to weird problems. If you only have a dumb value-store, it should be fine. Read this:



          https://stackoverflow.com/questions/28250710/qt-5-4-qml-prevent-binding-loop



           Architecture



          Here's how I implemented my application (sorry for any bugs, I don't have the source code here):



          QML:



          CheckBox 
          checked: Settings.everythingOk
          onCheckedChanged: Settings.everythingOk = checked



          C++ (not sure about the syntax)



          class Settings: public QObject 
          Q_OBJECT
          Q_PROPERTY(bool everythingOk MEMBER m_everythingOk NOTIFY everythingOkChanged)

          signals:
          void everythingOkChanged();

          private:
          bool m_everythingOk = false;



          and then I exposed Settings as a global singleton to QML. (It's also possible to expose it as a normal object if multiple instances are required.)



          To me this seems much simpler.



          Yes, it's slightly more to write, but not much. Your trick is clever, but it's not as future-proof as using a more standard approach.






          share|improve this answer















          I've developed my first QML application some months ago, so I'm far from an expert in QML. Here are some of my thoughts:



          Loading a QML file from disk vs. embedding it



          Nothing wrong about either of those.



          Modify properties in response to UI actions (instead of calling Q_INVOKABLE functions that sends data to the control system)



          That's called two-way bindings. The can be fine, but often leads to weird problems. If you only have a dumb value-store, it should be fine. Read this:



          https://stackoverflow.com/questions/28250710/qt-5-4-qml-prevent-binding-loop



           Architecture



          Here's how I implemented my application (sorry for any bugs, I don't have the source code here):



          QML:



          CheckBox 
          checked: Settings.everythingOk
          onCheckedChanged: Settings.everythingOk = checked



          C++ (not sure about the syntax)



          class Settings: public QObject 
          Q_OBJECT
          Q_PROPERTY(bool everythingOk MEMBER m_everythingOk NOTIFY everythingOkChanged)

          signals:
          void everythingOkChanged();

          private:
          bool m_everythingOk = false;



          and then I exposed Settings as a global singleton to QML. (It's also possible to expose it as a normal object if multiple instances are required.)



          To me this seems much simpler.



          Yes, it's slightly more to write, but not much. Your trick is clever, but it's not as future-proof as using a more standard approach.







          share|improve this answer















          share|improve this answer



          share|improve this answer








          edited Jan 25 at 20:07


























          answered Jan 25 at 19:49









          Georg Schölly

          1166




          1166











          • Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
            – Fab
            Jan 26 at 15:53











          • @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
            – Georg Schölly
            Jan 26 at 19:37










          • Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
            – Fab
            Jan 27 at 20:01











          • @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
            – Georg Schölly
            Feb 1 at 8:27
















          • Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
            – Fab
            Jan 26 at 15:53











          • @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
            – Georg Schölly
            Jan 26 at 19:37










          • Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
            – Fab
            Jan 27 at 20:01











          • @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
            – Georg Schölly
            Feb 1 at 8:27















          Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
          – Fab
          Jan 26 at 15:53





          Thank you for your kind reply. I get the point about circular dependency. Having a unique "driving" property instead of a "two way" control makes a lot of sense (checkBox.checked property in my code, this differs from what C#/WPF does with its properties). I kindly ask you to help me understand why I should consider my code not so "future-proof"; I thought that if my code is not going to work it would be in a next major QT release, where many other things might break...
          – Fab
          Jan 26 at 15:53













          @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
          – Georg Schölly
          Jan 26 at 19:37




          @Fab First of all a big caveat: I don't completely understand what the advantages of your architecture are, so I might be coming from a wrong angle. I don't think the code will stop working, but in my opinion it's not future proof in 2 ways: (1) it's an uncommon design, every developer who's going to work on it will first have to understand the design, (2) It's possible that this design works in your test project but has disadvantages / problems you will only find later. A standard architecture is a safer choice.
          – Georg Schölly
          Jan 26 at 19:37












          Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
          – Fab
          Jan 27 at 20:01





          Your points sound reasonable and fair. I understand that the perspective is important (I was trying to simplify management of a system where more than 100 properties have to be kept in sync with a PLC; I was trying to reduce code duplication and locations where the same properties have to be declared by name. I could have done it by using dynamic properties (setProperty) but I did not find a way to bind them to QML. BTW I'll think about different ways to reach the same purpose with a more standard approach. Thank you!
          – Fab
          Jan 27 at 20:01













          @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
          – Georg Schölly
          Feb 1 at 8:27




          @Fab I've made good experience with code generation, e.g. use Python to generate your C++ backend.
          – Georg Schölly
          Feb 1 at 8:27












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185910%2fqt-qml-scripting-and-property-binding-approach%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Chat program with C++ and SFML

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          Will my employers contract hold up in court?