When you need to expose C++ object for accessing in QML, you may have to write a lot of annoying and trivial Q_PROPERTY()
s, getters, setter slots, signals, and private member variables. They will makes your class a mess (any mostly are duplicated). For example, a QString myFoo
:
1 | class MyObjectExposedToQml : public QObject |
Though only one property here but has been nearly create a getter/setter/signal/variable hell. So make some macros to get rid of these shit:
Important: in macro definition,
signals:
andslots:
must be replaced withQ_SIGNALS:
andQ_SLOTS
. Otherwise compilation will fail.
(this problem cost me hours to find out…)
1 |
|
For those who have ever used Angular / Vue and their data-binding
If you have ever used Angular / Vue, you should be familiar with its easy-to-use data-binding; framework will aggressively watch if any value in model is modified, then update view automatically. But QML is not that smart.
This is how QML’s data-binding syntax looks like:
1
2
3 Button {
text: my_object_exposed_to_qml.myFoo
}
Equivalent to JS’s
1
2
3
4
5
6 Button {
Component.onCompleted: {
// Qt.binding() is required, otherwise Button.text won't be updated when myFooChanged() signal is emitted.
text = Qt.binding(function(){ return my_object_exposed_to_qml.myFoo })
}
}
QML’s property binding actually relys on Qt’s signal, (e.g.NOTIFY myFooChanged
above), QML itself will NOT aggressively watch the modification from getter function. The specified signal (NOTIFY signalFunctionName
) must be invoked (e.g.emit myFooChanged
), then QML side can know that the value of property is changed.
Therefore, in C++, use setter (or emit signal manually) instead of assigning the member variable directly, otherwise QML won’t be notified when the value is changed.
Usage
1 | class MyObjectExposedToQml : public QObject |
Oh yeah!
Surely it’s not a good practice to place function definition in header. But if you need, you can think how to do that. (This is against the topic of this article.)