Solved Why is this a binding loop?
-
@mzimmers said in Why is this a binding loop?:
At runtime I get an error about a binding loop on "model." The error was introduced when I put in the emit() call. What might I be doing wrong?
First you should understand how binding loops are detected, therefore take a look at this video from KDAB: Introduction to Qt / QML (Part 11) - Binding Loops.
Now to solve your issue: remove the emit in the getter. You should only emit a notification on property value change, the purpose of this is to enable QML to be aware about changes. So property changes on C++ side can automatically trigger updates on QML side.
If you trigger notification in C++ side with the getter, then:- QML is reading property with getter
- QML is notified about property value change
- QML reread property value with getter
- QML is notified about property value change
- QML detect binding loop!
-
Thank you both for the help. To answer your question about why there was a signal on a get -- the way this app was written, the get not only returned the current value, but also updated it first (I know it's weird).
To fix this, I've created a setter for the property:
QStringList ChangeConsumables::GetPosterModalChecklist() { return m_posterModalChecklist; } void ChangeConsumables::SetPosterModalChecklist(QStringList qsl) { m_posterModalChecklist = qsl; emit EventPosterModalChecklistChangedForQML(m_posterModalChecklist); }
The code is a little convoluted, as the setter is actually invoked by another object (the same one that's providing the QStringList to the getter), but it seems to work.
Thanks again...
-
Hi,
There's one thing missing from your setter: the equality guard. Usually the first thing done in a setter is check if the value changes and stop there if not. This allows to avoid signal storms were each party connected re-emits the same values over and over.
-
@SGaist so, like this?
void ChangeConsumables::SetPosterModalChecklist(QStringList qsl) { if (m_posterModalChecklist != qsl) { m_posterModalChecklist = qsl; emit EventPosterModalChecklistChangedForQML(m_posterModalChecklist); } }
-
Either that or
void ChangeConsumables::SetPosterModalChecklist(QStringList qsl) { if (m_posterModalChecklist == qsl) { return; } m_posterModalChecklist = qsl; emit EventPosterModalChecklistChangedForQML(m_posterModalChecklist); }
Depending on your taste.
Note that I have seen this version more frequently. Also in Qt's own sources. -
@SGaist I realize I'm old school, but I really don't like return statements in the middle of a function. I know it's done by far better coders than I, but I'm just not a fan.
-
I understand your point.
IIRC, early returns like these may allow some optimization by the compiler.
It's technically also at least one less operation because != is usually implemented as ! ==.
-
Not to be argumentative, but I'd venture that a routine that is comparing QStringList objects probably leaves much to be desired in the optimization department anyway.
Your comment about !== is interesting. Is there a way for the programmer to explicitly effect a similar comparison?
-
@mzimmers said in Why is this a binding loop?:
Not to be argumentative, but I'd venture that a routine that is comparing QStringList objects probably leaves much to be desired in the optimization department anyway.
I was more in the generic case of simple type comparison :-)
@mzimmers said in Why is this a binding loop?:
Your comment about !== is interesting. Is there a way for the programmer to explicitly effect a similar comparison?
I am not sure I am following you on that one.
-
@SGaist said in Why is this a binding loop?:
I am not sure I am following you on that one.
Well, of course C++ doesn't have a "!==" operator, so I assumed you meant that it first compares type, then content (a la Javascript). I was just curious how a C++ coder might perform that type check explicitly.
-
You missed the space between the ! and the == :-)
I meant it as: "!(a == b)"
-
Oh...I hate it when I do that (heh).
But now my statement on efficiency is even more true...
EDIT:
For those who really wish to exact that last bit of optimization, you could always do something like this:
void ChangeConsumables::SetPosterModalChecklist(QStringList qsl) { do { if (m_posterModalChecklist == qsl) { continue; } if (any other reasons to exclude further processing) { continue; } m_posterModalChecklist = qsl; emit EventPosterModalChecklistChangedForQML(m_posterModalChecklist); } while (false); }
This technique is also very handy for avoiding multiple if statements (with their annoying attendant indentation).