BB10 Cascades Minimum Template

While getting to learn BB10 Cascades and Native, one of the most annoying issue is trying to figure out where to start with the project. When you create a new BlackBerry Project using QNX Momentics IDE, you can select from either Native or Cascades. From there, you can select different levels of templates. For the Cascades templates, you can either choose Standard empty project, List View, Tabbed Pane or Navigation Pane. This would be fine if you were going to do everything needed just in Cascades. But, (I’m new to this, so I could be wrong), if you want to add c++ function calls from the QML pages, the templates are a little lacking. What makes it even more confusing is going to the Cascade Examples on GitHub and following along with what they did, which doesn’t have the file and code layout given from the templates. So, I decided to see what would be the minimum setup in order to call a simple c++ function from a qml page.

I started with the Standard empty project and used the Sensor Demo as a guide for getting the basic layout.

After creating the project, the first thing to do is fix the file names for the c++ section.  In the examples, they use file names that are similar to the name of the project.  I don’t know why the IDE doesn’t do this, but it also doesn’t setup the project the same. Since I name the project HelloWorldMinimum, I will name the class files HellowWorldServices.

Rename the mail c++ files to match closer to the project name
Rename the mail c++ files to match closer to the project name

You also have to make sure you rename the include call in the newly name HelloWorldServices.cpp to reflect the new header file name.  This change is also needed in the main.cpp file as well.


#include "HelloWorldServices.hpp"

Next you will need to rename the classes within the both source and header file to match the new name.  You would think this would be done automatically when you rename the files, but I guess there’s a reason that they aren’t.  Also, part of this minimal setup is making the main.cpp file actually the main class.  The application calls in the original applicationui.cpp and application.hpp need to be removed and replaced by simple QObject type calls to the parent.

Rename the class and change the function and types
Rename the class and change the function and types

class HelloWorldServices : public QObject
{
   Q_OBJECT
public:
   HelloWorldServices(QObject *parent = 0);
   virtual ~HelloWorldServices() { }

Finally, the Translation function needs to be moved to the main.cpp as well as declaring the root of the application.


Application app(argc, argv);

// localization support
QTranslator translator;
const QString locale_string = QLocale().name();
const QString filename = QString::fromLatin1("HelloWorldMinimum_%1").arg(locale_string);
if (translator.load(filename, "app/native/qm")) {
  app.installTranslator(&translator);
}

QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(&app);
AbstractPane *root = qml->createRootObject<AbstractPane>();

app.setScene(root);

return Application::exec();

When everything looks okay (I’ll have the complete code below), then you can build the project.  You should get an error reminding you that you forgot to clean the project of the old pointers to the old file names.

Fix the errors by cleaning the project and building again
Fix the errors by cleaning the project and building again

Simply choose Clean Project and the Build Configurations > Build All to build the project again.

From here you can put the hook into call the class in the main.cpp.


qmlRegisterType<HelloWorldServices>("HelloWorldServices", 1, 0, "HelloWorldServices");

Once this is there, then you can easily call any function in the class from the qml page.  In my example, I simply put in a call to a getHello() function from the class that will return a QString value of “Hello there!”  After registering the HellowWorldServices, I can easily import it the qml and IDE recognizes it for the code help.


import HelloWorldServices 1.0

After it is imported, then you need to attach it as an object, so that you can call the functions.


onClicked: {
taHelloResults.text = hws.getHello();
}

That’s it!  I plan on seeing if calling c++ classes from another c++ class is now easier with this setup and I’ll make a post when I figure it out.  For now, here is the full code for each page.

main.cpp


#include "HelloWorldServices.hpp"

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

#include <QLocale>
#include <QTranslator>

#include <Qt/qdeclarativedebug.h>

using namespace bb::cascades;

Q_DECL_EXPORT int main(int argc, char **argv)
{
  Application app(argc, argv);

  qmlRegisterType<HelloWorldServices>("HelloWorldServices", 1, 0, "HelloWorldServices");

  // localization support
  QTranslator translator;
  const QString locale_string = QLocale().name();
  const QString filename = QString::fromLatin1("HelloWorldMinimum_%1").arg(locale_string);
  if (translator.load(filename, "app/native/qm")) {
    app.installTranslator(&translator);
  }

  QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(&app);
  AbstractPane *root = qml->createRootObject<AbstractPane>();

  app.setScene(root);

  return Application::exec();
}

HelloWorldServices.cpp


#include "HelloWorldServices.hpp"

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

using namespace bb::cascades;

HelloWorldServices::HelloWorldServices(QObject *parent) :
   QObject(parent)
{

}

QString HelloWorldServices::getHello()
{
  return QString("Hello there!");
}

HelloWorldServices.hpp


#ifndef ApplicationUI_HPP_
#define ApplicationUI_HPP_

#include <QObject>

namespace bb
{
  namespace cascades
  {
    class Application;
    class LocaleHandler;
  }
}

class HelloWorldServices : public QObject
{
  Q_OBJECT
  public:
  HelloWorldServices(QObject *parent = 0);
  virtual ~HelloWorldServices() { }

  public Q_SLOTS:
  QString getHello();

  private slots:

  private:

};

#endif /* ApplicationUI_HPP_ */

main.qml


import bb.cascades 1.2
import HelloWorldServices 1.0

Page {
  Container {
  //Todo: fill me with QML
    Label {
    // Localized text with the dynamic translation and locale updates support
      text: qsTr("Hello World") + Retranslate.onLocaleOrLanguageChanged
      textStyle.base: SystemDefaults.TextStyles.BigText
    }

    TextArea {
      id: taHelloResults
      minHeight: 500
    }

    Button {
      id: btnGetHello
      text: "Test Hello"

      onClicked: {
         taHelloResults.text = hws.getHello();
      }
    }
  }
  attachedObjects: [
      HelloWorldServices {
         id: hws
      }
   ]
}

About DeanLogic
Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.

About DeanLogic

Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.