I want to bind a method of a C++ class to a QML component property and re-evaluate it when a dependent property changes. The following QML component does what I want:
// Converter.qml:
import QtQuick 2.0
QtObject {
    property double rate: 1
    function exchange(amount) { return amount * rate }
}
If I assign the result of the exchange function to a property like so,
Text { text: converter.exchange(100) }
the Text element will automatically update when rate is changed.  This works with a QML component, but I do not know how to do it with a C++ class.
I would like to implement a functionally equivalent class in C++:
#include <QObject>
class Convert : public QObject
{
    Q_OBJECT
    Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged)
public:
    explicit Convert(QObject *parent = 0)
        : QObject(parent), m_rate(1.0)
    { }
signals:
    void rateChanged();
public slots:
    double exchange(double amount) { return m_rate * amount; }
    double rate() { return m_rate; }
    void setRate(double r) {
        m_rate = r;
        emit rateChanged();
    }
private:
    double m_rate;
};
The rate property is accessible from QML, but changing it does not signal to the QML engine that 'exchange' should be re-evaluated. 
Here is my main.qml:
// main.qml
import QtQuick 2.1
import QtQuick.Controls 1.1
import Utils 1.0
ApplicationWindow {
    width: 300; height: 200
    visible: true
//    Converter { id: converter; rate: rateField.text }
    CppConverter { id: converter; rate: rateField.text }
    Column {
        TextField { id: rateInput; text: '0.41' }
        TextField { id: amountInput; text: '100.00' }
        Text { id: output; text: converter.exchange(amountField.text).toFixed(2) }
    }
}
If I enable the CppConverter, the output is updated when I change the amountInput, but not when I change the rateInput.  If I comment-in the QML Converter element, the update works fine.
With the QML Converter, the QML runtime identifies the dependency on the rate property and re-evaluates the exchange function when the rate is changed. How can I indicate to the QmlEngine to do the same in the C++ version?
There's no way to do this currently.
I don't think relying on a function being re-evaluated like this is a good practice, though. You should either explicitly call it when necessary:
Connections {
    target: converter
    onRateChanged: output.text = converter.exchange(amountField.text)
}
Or convert exchange() into a property, and approach it declaratively instead of imperatively (code not complete or tested):
class Convert : public QObject
{
    // ...
    Q_PROPERTY(double amount READ amount WRITE setAmount NOTIFY amountChanged)
    Q_PROPERTY(double exchange READ exchange NOTIFY exchangeChanged)
    // ...
public:
    double exchange() { return m_rate * m_amount; }
private:
    double m_rate;
    double m_amount;
};
You'd then need to emit the various *Changed signals, etc. in the appropriate places.
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