Running C++ Function from QML (Trivial Example)

BlackBerry 10 Cascades C++ QML

When I first read about Cascades “they” said use QML for the UI and C++ for the logic.  Okay, great so I wrote a function in C++ and made a pretty UI in QML… Now what?  In this example I’ll go through the steps it takes to call a C++ function from the QML.  However this example won’t have a pretty UI.

This example will take two user inputs, number of items and price per item, and computes the price of all the items after a 5% sales tax.

1. Create a basic UI with a few Labels, TextFields, and a Button.

main.qml:

import bb.cascades 1.0

Page {
content: Container {
Label {
text: qsTr("Enter the number of items purchased: ")
}
TextField {
id: in1
objectName: "in1"
}
Label {
text: qsTr("Enter the price per item ($):")
}
TextField {
id: in2
objectName: "in2"
}
Button {
id: button
objectName: "button"
text: "Compute"
onClicked: {

}
}
Label {
id: total
objectName: "total"
text: "Final bill, including 5% tax, is $____"
}
}
}

Screen:

2. Write a function in C++ that performs the required operation.  I have named my function “clickedButton” with two variables “number” and “price”.  These will be replaced by user inputs from the QML

clickedButton(int number, int price)
{
    const double TAX_rate = 0.05;
    double subtotal;

    subtotal = price*number;
    return (subtotal+subtotal*TAX_rate);

}

3. Now add this function to the <nameofyourproject>.cpp (The name of my project in the code below is “QMLandCPP”) and set the context property.  I have set it as “app” in the line: qml->setContextProperty(“app”, this);

<nameofyourproject>.cpp:

#include "QMLandCPP.hpp"

#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>

using namespace bb::cascades;

QMLandCPP::QMLandCPP(bb::cascades::Application *app)
: QObject(app)
{

QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
qml->setContextProperty("app", this);

AbstractPane *root = qml->createRootObject<AbstractPane>();

app->setScene(root);
}


double QMLandCPP::clickedButton(int number, int price)
{
const double TAX_rate = 0.05;
double subtotal;

subtotal = price*number;
return (subtotal+subtotal*TAX_rate);
}

4. This function must be declared in header file, <nameofyourproject>.hpp.  So add the function to the file as a Q_INVOKABLE.

<nameofyourproject>.hpp:

#ifndef QMLandCPP_HPP_
#define QMLandCPP_HPP_

#include <QObject>

namespace bb { namespace cascades { class Application; }}

class QMLandCPP : public QObject
{
Q_OBJECT
public:
QMLandCPP(bb::cascades::Application *app);

Q_INVOKABLE double clickedButton(int number, int price);

virtual ~QMLandCPP() {}

};

#endif

5. Now back to the QML add the function call inside of the onClicked parameter of the button.  Since we want the text from the TextField id “in1” for the first variable we call “in1.text” and same for TextField id “in2” we call the second variable as “in2.text”.  As you know from C++ these two will now take the place of “number” and “price”, respectively, in our function.  And we want this output to be shown in the Label id “total” so the onClicked sends it to “total.text”

...          
onClicked: {
                total.text = "Final bill, including 5% tax, is $" + app.clickedButton(in1.text, in2.text);
            }
...

6. Run the app to test:

NOTE: This is a trivial example because you do not need to C++ to do this calculation.  The onClicked of the button could have simply been:

total.text = "Final bill, including 5% tax, is $" + (in1.text*in2.text+(in1.text*in2.text*0.05));

And it will produce the same result without needing to write a function and add it to the <nameofyourproject>.cpp or <nameofyourproject>.hpp files in the first place.  However this strategy can be used to call much more complicated C++ functions that you would not want to write inline of the onClicked.

Tags: C++ QML Example