I have the habit of writing my "propertyChanged" signal
s with an argument, such that the receiving end doesn't need to call the Q_PROPERTY
's READ
function explicitly.
I do this out of clarity and the assumption that in a QML data binding situation, no "expensive" call to the getter needs to be done to actually fetch the value, as it's already passed to QML as a signal argument.
My colleagues disagreed and said it was against "QML style", to which I responded the documentation clearly states it may have an argument that will take the new value of the underlying member:
NOTIFY
signals forMEMBER
variables must take zero or one parameter, which must be of the same type as the property. The parameter will take the new value of the property.
Nowhere in the documentation is it stated that the QML binding system uses this parameter to prevent an additional function call to the getter when handling the signal. I understand this call will probably be made from C++, so no "expensive" QML to C++ call will be made, but it still is an extra function call, which in principle could result in a visible performance penalty in case of many updates.
I tried inspecting the QML binding source code, but couldn't infer anything from it. I wonder if someone knows what the deal is: is the signal argument used or not?
I wonder if someone knows what the deal is: is the signal argument used or not?
Here's one way to check:
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QDebug>
class MyType : public QObject
{
Q_OBJECT
Q_PROPERTY(bool foo READ foo WRITE setFoo NOTIFY fooChanged)
public:
MyType(QObject *parent = nullptr) :
QObject(parent),
mFoo(0)
{
}
bool foo() const
{
qDebug() << Q_FUNC_INFO;
return mFoo;
}
void setFoo(bool foo)
{
if (foo == mFoo)
return;
mFoo = foo;
emit fooChanged(mFoo);
}
signals:
void fooChanged(bool foo);
private:
bool mFoo;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
qmlRegisterType<MyType>("App", 1, 0, "MyType");
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
#include "main.moc"
main.qml:
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import App 1.0
Window {
width: 400
height: 400
visible: true
Switch {
id: fooSwitch
}
MyType {
id: myType
foo: fooSwitch.checked
onFooChanged: print("onFooChanged, foo =", foo)
// onFooChanged: print("onFooChanged myType.foo =", myType.foo)
}
}
The output when switching back and forth is:
qml: onFooChanged, foo = true
qml: onFooChanged, foo = false
So it's safe to say that the value is used and not the getter.
To see what the output would have been like if the signal argument hadn't been used, uncomment the commented out line and comment out the other one:
bool __cdecl MyType::foo(void) const
qml: onFooChanged myType.foo = true
bool __cdecl MyType::foo(void) const
qml: onFooChanged myType.foo = false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With