Qt Commercial Support Weekly #18: Using QVariantMap to Emulate Passing by Reference and Pointer in QML

When you are combining QML with C++ code it is possible to call a function in your class from the QML in order to do some specific handling that you don't want to do in the QML code.  This function can be a slot or it can be another member that has been marked with Q_INVOKABLE. This post won't go into detail on how to get that setup but it will focus on how to get around the fact that you cannot pass by reference or pointer from QML to C++.  Let's say that you have a function like this:

 

                Q_INVOKABLE void testFunction(int &a, int &b)

                {

                                a += 5;

                                b += 10;

                }

 

If this is called from within C++ then it will work fine, however, if you want to call this function from QML like this:

 

                var a = 1;

                var b = 1;

                externalClass.testFunction(a, b);

                print(a);

                print(b);

 

Then it will not be able to run the QML code because it cannot match up with the reference to the int variables in the testFunction function.  If they were just passed as plain integers, then it would work, but then we would not be able to get access to the modified variables as the referencing benefit would have been lost.

 

So, in order to deal with this particular scenario we need to use QVariantMap to take care of this setup.  We have two options here, we can either modify the existing function or we can add one that would add as a wrapper for QML, if we need the original one to stay intact for existing C++ related functionality.  In this case I will just modify the existing one.  In order to be able to enable QML to at least be able to call this function we need to change the parameters to be plain integers and not references to them.  In addition, we need to return a QVariantMap from this function so the function should look like this:

 

                Q_INVOKABLE QVariantMap testFunction(int a, int b)

 

Now, all that is left to do is to take the existing functionality and extend it so that it puts the results into a QVariantMap and returns it.  When we insert into the QVariantMap we need to give a name for the variables being stored in it so that we can easily access them on the QML side. For convience, I will just use aInt and bInt.  So, we need to do something like:

 

                a += 5;

                b += 10;

                QVariantMap map;

                map.insert("aInt", a);

                map.insert("bInt", b);

                return map;

 

And that is all there is to it on the C++ side of things.  The only thing left to do is to fix up the QML side of the application.  Since we know that we will be getting the results in a QVariantMap, then we just need to put that in a variable and then print the results from that, so this is luckily fairly straightforward to do and can be done like:

 

                var a = 1;

                var b = 1;

                var resultMap = externalClass.testFunction(a, b);

                print(resultMap.aInt);

                print(resultMap.bInt);

 

In the print statements we refer to the names we gave the variables, this makes it easy to access any given variable inside the QVariantMap.  There you have it - a simple way to get around the fact that you cannot pass by reference or pointer, and if you go with the route of wrapping around the existing function then you can easily have the best of both worlds.

 

Until next time, happy coding :)


Comments