Wednesday, May 2, 2012

[Tutorial] QML with a C++ Backend

Recently I posted that I had uploaded my first ever QML application to Google Play.  I was pretty excited about that, but since then I've really wanted to have a C++ backend so that I can access more advanced features (settings, networking, etc) and data models.  Well, after playing around for a day or two, I finally figured out how to do that!  It's quite simple, really (thankfully!).

Most of the tutorials that I found for doing this left out parts of the code, which frustrated me greatly because then I could not figure out how and why they did things the way that they did.  To help avoid that issue, I'll post an archive of my source here so that no questions are left unanswered!

For an alternate tutorial, check here.

Step 1: Setting up the base of the application
I created a normal "Qt GUI" project using the SDK's wizard.  That created the *.pro, main.cpp, mainwindow.h and mainwindow.cpp files for me.  I then added a Qt Resource File (QRC) for holding the QML file (something that has to be done in order for QML to work on Android).  Then, I added a new, standalone QML file to the project.  These files will be the base for the application.

Step 2: Setting up the base of the UI
In the mainwindow.ui file, I added a QDeclarativeView that I would use to display the QML file.  In the mainwindow.cpp code (in the constructor), I added "this->setCentralWidget(ui->declarativeView);" right after the UI setup code is run.  This makes my QDeclarativeView fill up my entire UI and expand with it.

Step 3: Making the backend
This is a pretty simple step.  Start by adding a new class that inherits QObject (important!!!) to your project (I called mine "Logic").  For my Logic class, I wanted it to have a private bool that I could set and return the value of.  For the set and return functions, you can either use public slots or "Q_INVOKABLE".  I used slots because I was already familiar with them and because it would make more sense to use slots in case I wanted to tie more classes in with my "Logic" class.

Step 4: Linking the backend to the frontend
This is the part that took me longer than it should have.... First off, in mainwindow.cpp, declare two pointers: a QDeclarativeEngine (*engine) and a QDeclarativeContext (*cntx).  Set them to "ui->declarativeView->engine()" and "engine->rootContext()".  Next, to complete the linkage, use "cntx->setContextProperty("Logic", new Logic);".  Finally, use "ui->declarativeView->setSource(QUrl source);" to set the source of your QDeclarativeView to your QML file (located in your QRC).

Note
When calling "cntx->setContextProperty("Logic", new Logic);", the first argument is the string that you're going to use to call the functions in your QML file while the second argument is a object of class type Logic (in this case).  


Step 5: Calling your functions in QML
Once steps 1-4 have been completed, step 5 is as simple as "Logic.toggledNow()" in my case.  In "foo" terms, it would be "Foo.someFunction()" if you used cntx->setContextProperty("Foo", new myClass); earlier.

I hope this tutorial has helped you out and thanks for stopping by!

Chris K

1 comment: