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. updating display of property
Qt 6.11 is out! See what's new in the release blog

updating display of property

Scheduled Pinned Locked Moved Solved QML and Qt Quick
12 Posts 5 Posters 1.9k Views 2 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.
  • mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by
    #1

    Hi all -

    I realize my title isn't very descriptive, but I didn't know how else to word it.

    I have a class that I use in QML:

    class Schedule : public QObject
    {
        Q_OBJECT
        QML_ELEMENT
    
        QTime m_startTime = QTime(12, 0);
        Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)
        QTime startTime() { return m_startTime; }
        bool setStartTime(QTime startTime);
    
        Q_INVOKABLE QString makeTimeLabel(bool isStartTime, float timeZoneOffset)
        {
           // do a lot of stuff here
        }
    }
    

    I use this function in my QML:

    Item {
        property Schedule schedule
    
    	Label {
    		text: schedule.makeTimeLabel(false, timeZoneOffset)
    

    As you can see, this works when the QML is first loaded, but the function doesn't get called to update the display when the member object is changed.

    Is there a way to somehow "bind" (I know that's not the right word) the property to the function in order to get automatic updates?

    Thanks...

    JoeCFDJ GrecKoG 2 Replies Last reply
    0
    • mzimmersM mzimmers

      Hi all -

      I realize my title isn't very descriptive, but I didn't know how else to word it.

      I have a class that I use in QML:

      class Schedule : public QObject
      {
          Q_OBJECT
          QML_ELEMENT
      
          QTime m_startTime = QTime(12, 0);
          Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)
          QTime startTime() { return m_startTime; }
          bool setStartTime(QTime startTime);
      
          Q_INVOKABLE QString makeTimeLabel(bool isStartTime, float timeZoneOffset)
          {
             // do a lot of stuff here
          }
      }
      

      I use this function in my QML:

      Item {
          property Schedule schedule
      
      	Label {
      		text: schedule.makeTimeLabel(false, timeZoneOffset)
      

      As you can see, this works when the QML is first loaded, but the function doesn't get called to update the display when the member object is changed.

      Is there a way to somehow "bind" (I know that's not the right word) the property to the function in order to get automatic updates?

      Thanks...

      GrecKoG Offline
      GrecKoG Offline
      GrecKo
      Qt Champions 2018
      wrote on last edited by GrecKo
      #9

      You defined a property with

      Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)

      and used the following binding in QML:

      text: schedule.makeTimeLabel(false, timeZoneOffset)

      From this line, the QML engine has no way of knowing that this depends on the startTime property, so emitting its notify signal won't reevaluate the binding.

      For property bindings to work and be updated, the property has to be mentioned in the binding.

      A hacky solution could be:
      text: schedule.startTime, schedule.makeTimeLabel(false, timeZoneOffset)
      Where the comma just ignore the first value and return the one after.
      But as I said this is hacky.

      What has been recommended is adding a timeLabel property but I don't really like that, since this is exposing UI data in your business layer. The actual data is the startTime. And you can't pass parameters to it.

      What I would recommended is adding a function taking the time in parameter and returning a string.

      Does the formatting function actually depends on the Schedule class or is this just a generic time formatting? from the isStartTime I believe this is the former.

      One could want to move it outside of the Schedule class to not mix your business and presentation layers. But you can keep it in Schedule if you want. I like to have a Formatter class that does all my formatting.

      Add a Q_INVOKABLE QString formatScheduleTime(QTime time, bool isStartTime, float timeZoneOffset) function.

      Then you just have to use it as the following:

      text: schedule.formatScheduleTime(schedule.startTime, false, timeZoneOffset) // why is isStartTime false here is another question (:
      

      and since the QML engine can see that the startTime property is used, the text will be updated when startTimeChanged is emitted.

      mzimmersM 1 Reply Last reply
      3
      • mzimmersM mzimmers

        Hi all -

        I realize my title isn't very descriptive, but I didn't know how else to word it.

        I have a class that I use in QML:

        class Schedule : public QObject
        {
            Q_OBJECT
            QML_ELEMENT
        
            QTime m_startTime = QTime(12, 0);
            Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)
            QTime startTime() { return m_startTime; }
            bool setStartTime(QTime startTime);
        
            Q_INVOKABLE QString makeTimeLabel(bool isStartTime, float timeZoneOffset)
            {
               // do a lot of stuff here
            }
        }
        

        I use this function in my QML:

        Item {
            property Schedule schedule
        
        	Label {
        		text: schedule.makeTimeLabel(false, timeZoneOffset)
        

        As you can see, this works when the QML is first loaded, but the function doesn't get called to update the display when the member object is changed.

        Is there a way to somehow "bind" (I know that's not the right word) the property to the function in order to get automatic updates?

        Thanks...

        JoeCFDJ Offline
        JoeCFDJ Offline
        JoeCFD
        wrote on last edited by
        #2

        @mzimmers do you
        emit startTimeChanged
        when m_startTime is changed.

        mzimmersM 1 Reply Last reply
        0
        • JoeCFDJ JoeCFD

          @mzimmers do you
          emit startTimeChanged
          when m_startTime is changed.

          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #3

          @JoeCFD yes, and I've verified that it is indeed emitted. If I use the property itself, it updates, but since I've introduced this intermediate function, it doesn't. That's why I was wondering if there was some way to tie the function to the property, or at least automate it in the QML.

          JoeCFDJ 1 Reply Last reply
          0
          • mzimmersM mzimmers

            @JoeCFD yes, and I've verified that it is indeed emitted. If I use the property itself, it updates, but since I've introduced this intermediate function, it doesn't. That's why I was wondering if there was some way to tie the function to the property, or at least automate it in the QML.

            JoeCFDJ Offline
            JoeCFDJ Offline
            JoeCFD
            wrote on last edited by JoeCFD
            #4

            @mzimmers is the signal
            void startTimeChanged()
            defined?

            mzimmersM 1 Reply Last reply
            0
            • JoeCFDJ JoeCFD

              @mzimmers is the signal
              void startTimeChanged()
              defined?

              mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by mzimmers
              #5

              @JoeCFD said in updating display of property:

              @mzimmers is the signal
              void startTimeChanged()
              defined?

              Yes. Everything with the property itself is working fine. If I do this in my QML:

              Label {
                  text: schedule.startTime.toTimeString()
              

              then everything works fine; it's just not in the format I need. The problem is (I think) the C++ formatting function that doesn't get called just because the property gets updated. That's why I say I need some way to tie this function to the property, if that's even possible.

              The formatting is somewhat complex (involves time zone conversions, addition of AM/PM text, etc.) so I'd greatly prefer not to try to do it inline in the QML. I suppose I could use a JS function, and that might work, but first I wanted to see whether I could use my C++ function.

              EDIT:

              The JS function I wrote worked but only because I was using the approach that @GrecKo suggested.

              JoeCFDJ 1 Reply Last reply
              0
              • mzimmersM mzimmers

                @JoeCFD said in updating display of property:

                @mzimmers is the signal
                void startTimeChanged()
                defined?

                Yes. Everything with the property itself is working fine. If I do this in my QML:

                Label {
                    text: schedule.startTime.toTimeString()
                

                then everything works fine; it's just not in the format I need. The problem is (I think) the C++ formatting function that doesn't get called just because the property gets updated. That's why I say I need some way to tie this function to the property, if that's even possible.

                The formatting is somewhat complex (involves time zone conversions, addition of AM/PM text, etc.) so I'd greatly prefer not to try to do it inline in the QML. I suppose I could use a JS function, and that might work, but first I wanted to see whether I could use my C++ function.

                EDIT:

                The JS function I wrote worked but only because I was using the approach that @GrecKo suggested.

                JoeCFDJ Offline
                JoeCFDJ Offline
                JoeCFD
                wrote on last edited by
                #6

                @mzimmers can not you define another member variable
                QString m_startTimeString;
                in class Schedule and use it for Label in your qml directly?

                mzimmersM 1 Reply Last reply
                0
                • JoeCFDJ JoeCFD

                  @mzimmers can not you define another member variable
                  QString m_startTimeString;
                  in class Schedule and use it for Label in your qml directly?

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #7

                  @JoeCFD that occurred to me. Unfortunately, this class has several similar properties that all would have to have an attendant property just for display purposes. And it could get messy manually linking these properties.

                  Maybe I'll start by seeing if using a JS function will automatically update the text. As I said above, I'd greatly prefer to do this in C++ but a JS alternative isn't out of the question.

                  johngodJ kshegunovK 2 Replies Last reply
                  0
                  • mzimmersM mzimmers

                    @JoeCFD that occurred to me. Unfortunately, this class has several similar properties that all would have to have an attendant property just for display purposes. And it could get messy manually linking these properties.

                    Maybe I'll start by seeing if using a JS function will automatically update the text. As I said above, I'd greatly prefer to do this in C++ but a JS alternative isn't out of the question.

                    johngodJ Offline
                    johngodJ Offline
                    johngod
                    wrote on last edited by
                    #8

                    @mzimmers You need to create a Q_PROPERTY of type QString with a NOTIFY in your class. Something like

                    Q_PROPERTY(QString timeLabel READ timeLabel WRITE setTimeLabel NOTIFY timeLabelChanged)
                    

                    Update this property value inside the function makeTimeLabel(....), then bind this property in qml.

                    text: schedule.timeLabel
                    

                    This should work. Other ugly not so good option is to create a Timer in qml and use it to update the Label text, calling makeTimeLabel when the timer triggers.

                    1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      Hi all -

                      I realize my title isn't very descriptive, but I didn't know how else to word it.

                      I have a class that I use in QML:

                      class Schedule : public QObject
                      {
                          Q_OBJECT
                          QML_ELEMENT
                      
                          QTime m_startTime = QTime(12, 0);
                          Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)
                          QTime startTime() { return m_startTime; }
                          bool setStartTime(QTime startTime);
                      
                          Q_INVOKABLE QString makeTimeLabel(bool isStartTime, float timeZoneOffset)
                          {
                             // do a lot of stuff here
                          }
                      }
                      

                      I use this function in my QML:

                      Item {
                          property Schedule schedule
                      
                      	Label {
                      		text: schedule.makeTimeLabel(false, timeZoneOffset)
                      

                      As you can see, this works when the QML is first loaded, but the function doesn't get called to update the display when the member object is changed.

                      Is there a way to somehow "bind" (I know that's not the right word) the property to the function in order to get automatic updates?

                      Thanks...

                      GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote on last edited by GrecKo
                      #9

                      You defined a property with

                      Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)

                      and used the following binding in QML:

                      text: schedule.makeTimeLabel(false, timeZoneOffset)

                      From this line, the QML engine has no way of knowing that this depends on the startTime property, so emitting its notify signal won't reevaluate the binding.

                      For property bindings to work and be updated, the property has to be mentioned in the binding.

                      A hacky solution could be:
                      text: schedule.startTime, schedule.makeTimeLabel(false, timeZoneOffset)
                      Where the comma just ignore the first value and return the one after.
                      But as I said this is hacky.

                      What has been recommended is adding a timeLabel property but I don't really like that, since this is exposing UI data in your business layer. The actual data is the startTime. And you can't pass parameters to it.

                      What I would recommended is adding a function taking the time in parameter and returning a string.

                      Does the formatting function actually depends on the Schedule class or is this just a generic time formatting? from the isStartTime I believe this is the former.

                      One could want to move it outside of the Schedule class to not mix your business and presentation layers. But you can keep it in Schedule if you want. I like to have a Formatter class that does all my formatting.

                      Add a Q_INVOKABLE QString formatScheduleTime(QTime time, bool isStartTime, float timeZoneOffset) function.

                      Then you just have to use it as the following:

                      text: schedule.formatScheduleTime(schedule.startTime, false, timeZoneOffset) // why is isStartTime false here is another question (:
                      

                      and since the QML engine can see that the startTime property is used, the text will be updated when startTimeChanged is emitted.

                      mzimmersM 1 Reply Last reply
                      3
                      • mzimmersM mzimmers

                        @JoeCFD that occurred to me. Unfortunately, this class has several similar properties that all would have to have an attendant property just for display purposes. And it could get messy manually linking these properties.

                        Maybe I'll start by seeing if using a JS function will automatically update the text. As I said above, I'd greatly prefer to do this in C++ but a JS alternative isn't out of the question.

                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #10

                        Alternatively you may want to experiment with Q_OBJECT_COMPUTED_PROPERTY (I don't have experience with it myself, but looks like it may do the job.

                        https://doc.qt.io/qt-6/qobjectcomputedproperty.html

                        Read and abide by the Qt Code of Conduct

                        GrecKoG 1 Reply Last reply
                        0
                        • mzimmersM mzimmers has marked this topic as solved on
                        • GrecKoG GrecKo

                          You defined a property with

                          Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged FINAL)

                          and used the following binding in QML:

                          text: schedule.makeTimeLabel(false, timeZoneOffset)

                          From this line, the QML engine has no way of knowing that this depends on the startTime property, so emitting its notify signal won't reevaluate the binding.

                          For property bindings to work and be updated, the property has to be mentioned in the binding.

                          A hacky solution could be:
                          text: schedule.startTime, schedule.makeTimeLabel(false, timeZoneOffset)
                          Where the comma just ignore the first value and return the one after.
                          But as I said this is hacky.

                          What has been recommended is adding a timeLabel property but I don't really like that, since this is exposing UI data in your business layer. The actual data is the startTime. And you can't pass parameters to it.

                          What I would recommended is adding a function taking the time in parameter and returning a string.

                          Does the formatting function actually depends on the Schedule class or is this just a generic time formatting? from the isStartTime I believe this is the former.

                          One could want to move it outside of the Schedule class to not mix your business and presentation layers. But you can keep it in Schedule if you want. I like to have a Formatter class that does all my formatting.

                          Add a Q_INVOKABLE QString formatScheduleTime(QTime time, bool isStartTime, float timeZoneOffset) function.

                          Then you just have to use it as the following:

                          text: schedule.formatScheduleTime(schedule.startTime, false, timeZoneOffset) // why is isStartTime false here is another question (:
                          

                          and since the QML engine can see that the startTime property is used, the text will be updated when startTimeChanged is emitted.

                          mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by
                          #11

                          @GrecKo said in updating display of property:

                          What I would recommended is adding a function taking the time in parameter and returning a string.

                          This was exactly what I needed.

                          QString Schedule::formTimeString(QTime qt, double tzOffset) {
                              ...
                          

                          And @GrecKo 's explanation for how this work helped me understand the link between QML and QObjects better - thanks! It also explains why my JS function (which did accept a time argument) was working when my original C++ function was not. All in all, a very worthwhile exercise.

                          @kshegunov your idea is interesting, but I'm going to go with @GrecKo 's approach for this.

                          1 Reply Last reply
                          0
                          • kshegunovK kshegunov

                            Alternatively you may want to experiment with Q_OBJECT_COMPUTED_PROPERTY (I don't have experience with it myself, but looks like it may do the job.

                            https://doc.qt.io/qt-6/qobjectcomputedproperty.html

                            GrecKoG Offline
                            GrecKoG Offline
                            GrecKo
                            Qt Champions 2018
                            wrote on last edited by
                            #12

                            @kshegunov Q_OBJECT_COMPUTED_PROPERTY is meant for Bindable Properties, properties that are meant to also be used in C++ and that require more code involvement than just simple properties aimed just for QML.

                            Q_PROPERTY are not linked to their storage, so they can freely be "computed" and you don't have to specify it.

                            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