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 myFooChangedabove), 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.)