Getting a Q_INVOKABLE C++ function reevaluated by QML engine

Unfortunately, with all the normal magic of QML property bindings, getting a property updated in a setup that involves return values from functions isn’t really doable, like this:

I’m told there is a low priority feature request for a way of signalling that a function now returns a different value and all properties using it should be reevaluated.

I have so far discovered two different workarounds for that that I will be presenting here.

Using an extra property

Appending an extra property to trigger the reevaluation of the function is one way of doing it.

with the following on the C++ side:

This is a bit more code to write and to remember to use, but it does get the job done.

Intermediate layer
Another way is to inject an intermediate layer, an extra object, that has the function. It can even be simplified by having a pointer to itself.

with the following on the C++ side:

It seems a bit simpler for the reader on the QML side, but also gets the job done.

I am not sure which way is the best one, but the intermediate layer has a nicer feeling to it when more complicated types are involved.

2 comments on “Getting a Q_INVOKABLE C++ function reevaluated by QML engine
  1. Johan Thelin says:

    Isn’t this was read-only properties are for? To me, an invokable is something that you call from a piece of Javascript in an imperative way.

  2. kfunk says:

    Right, I think in this case you should try to turn this into a property. Functions which do not require arguments are suitable.

    With function carrying args, however, this “extra property trick” might be useful. Consider the following use-case:

    Image { id: someIcon; source: ThemeObject.fromTheme(“someIcon”) }

    ThemeObject is a QObject-based class for managing the current theme. ThemeObject::fromTheme(QString iconName) is Q_INVOKABLE function returning an icon based on the iconName and depending on the current theme. The icon name in this example is constant, we don’t care about that. But when the current theme changes we’d like ThemeObject.fromTheme(..) to be re-evaluated. Further assume there’s a ThemeObject::currentTheme property for the current theme.

    How to do that?

    => Create a wrapper function in QML/JS which has a property binding on both the icon name and the current theme.

    function customFromTheme(icon)
    {
    /* no-op for keeping a binding on this property */
    ThemeObject.currentTheme
    return ThemeObject.fromTheme(icon)
    }

    Now the initial example turns into:

    Image { id: someIcon; source: customFromTheme(“someIcon”) }

    => Works as expected, customFromTheme(..) is re-evaluated when the theme changes