updating display of property
-
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...
-
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...
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
startTimeproperty, 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.
-
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...
-
@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.
-
@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.
-
@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.
-
@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.
-
@mzimmers can not you define another member variable
QString m_startTimeString;
in class Schedule and use it for Label in your qml directly?@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.
-
@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.
@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.timeLabelThis 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.
-
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...
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
startTimeproperty, 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.
-
@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.
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.
-
M mzimmers has marked this topic as solved on
-
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
startTimeproperty, 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.
@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.
-
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.
@kshegunov
Q_OBJECT_COMPUTED_PROPERTYis 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.