Set up your project

Setting up an app is similar whether we're using QML or C++, so when we're done with the setup we build the UI both ways.

Create a project

Because we want to build this app from scratch, there's a little bit of setup that we need to take care of first. Let's start by creating an empty Cascades project to work from:

  1. In the Momentics IDE for BlackBerry, on the File menu, click New > BlackBerry Project.
  2. In the Project Type section, select Application > Cascades and click Next.
  3. In the Templates section, click Standard empty project and click Next.
  4. In the Project Name field, provide a name for your project (for example, MyFirstApp). Click Next.
  5. In the API Level page, select the API level that you want to use and click Finish.
  6. If you're prompted to open the QML Editing perspective, click Yes.

This tutorial is designed to use design units so that the UI looks great on all devices. You should select API level 10.3 or later.

When you open the QML Editing perspective, you are using the QML support tools, which are built into the Momentics IDE. If you have experience with Eclipse, most of the features of the IDE should be familiar to you.

You can find features that are specific to Cascades, such as the QML preview and Components view, using the QML Editing perspective.

To open the QML Editing perspective:

  1. Perform one of the following:
    • In Windows or Linux, click Window > Open Perspective > Other.
    • In Mac OS, click Momentics > Open Perspective > Other.
  2. Click QML Editing.
  3. Click OK.

After you finish creating a project from a template, a new project appears in the Project Explorer view with the project name that you specified. Your project is built automatically as soon as you create it. Take a peek in the Console view to see the results of the build.

You can see the files in your project in the Project Explorer view. The Project Explorer view is standard for Eclipse, but it has a few files that are specific to Cascades projects:

  • A .pro project file, which includes specific configurations and settings for your project
  • A standard Makefile for your project
  • An src folder for C++ source files
  • An assets folder for QML files and images

Import images

Now you need to import the assets required for the project. For the LightningCrossfade app, we need four images.

Daytime image asset for Cascades first app.
Nighttime image asset for Cascades first app.
Moon image asset for Cascades first app.
Sun image asset for Cascades first app.

day.jpg

The foreground image, which fades in as the slider moves to the right

night.jpg

The background image, which disappears as the foreground image fades in

moon.png

An icon used for the nighttime position of the slider

sun.png

An icon used for the daytime position of the slider

You'll notice that the images above assume that our app is running on a BlackBerry Z10 smartphone, which has a screen resolution of 768 x 1280. These images might not look good on all devices. If you want your app to support all BlackBerry 10 smartphones, you need images that scale to fit the screen resolution of all devices.We need to use a feature called static asset selection. This feature lets you use different sets of assets in your apps, depending on the resolution or theme of the device that your app is running on.

When you use asset selectors to manage different shapes of images, you should use asset selection based on layout. This technique lets you create folders of assets that fit on multiple devices with similar display shapes.

When you use asset selectors to manage different sizes of images, you can use asset selection based on screen density. This technique lets you create folders based on specific pixel per design unit values (ppd) instead of letting the framework scale your images for you. When you use ppd folders, Cascades selects the best fit for a particular device if there’s no default set of images.

To import images into your project:

  1. Download the crossfade_images.zip  file.
  2. Extract the contents of the .zip file to the project's assets folder in your workspace. For example, C:\<your_workspace>\<project_name>\assets.
  3. In the Project Explorer view, refresh your project to display the imported folders.

Let's look at the folders that you extracted in more detail:

  • In the10ppd folder, we store icons that suit devices that are fewer than ten pixels per design unit in screen density. The icons in this folder look good on most devices.
  • In the 12ppd folder, we store larger icons that suit the unique size of the BlackBerry Passport smartphone.
  • In the mindw7h6128du folder, we store images for devices that are shaped like the BlackBerry Z10 and BlackBerry Z30 smartphones.
  • In the mindw80h80du folder, we store images for devices that are shaped like the BlackBerry Q10, BlackBerry Q5, BlackBerry Passport, and BlackBerry Classic smartphones. We let Cascades scale these images to fit on these devices.
Screen showing project images and asset selectors based on screen density for Cascades first app in Project Explorer.

To learn about BlackBerry 10 devices, check out Device characteristics. To see a complete list of devices and their ppd values, see Design units.

Run the app

Even though the project is nearly empty, your app is ready to run. Let's build and run it to see the output.

Before you try to run the app, you need to make sure that you have a device or simulator set up as a launch target in the Momentics IDE.

For information about setting up the development environment, see Set up your environment.

To run the app:

  1. Click Run in the Launch mode drop-down list.
  2. Make sure that your app is selected in the Launch configuration drop-down list.
  3. Click Momentics IDE Launch button. to see the "Hello World" message.
Screen showing an app that uses the Standard empty template running on a device.

Check out the Console messages. You can review information about the settings that are active in your environment. For example, QML debugging is enabled and orientation support is set to automatic. You can learn more about these settings in Build, test, and deploy your app.

Learn how an app is started

Now that your app is running, let's have a closer look at how it's done. In the src folder, double-click the main.cpp file to open it in the editor.

#include "applicationui.hpp"

#include <bb/cascades/Application>

#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);

    // Create the Application UI object, 
    // This is where the main.qml file is
    // loaded and the application scene is set
    ApplicationUI appui;

    // Enter the application main event loop.
    return Application::exec();
}

The first few lines are the required include statements. The applicationui.hpp include is for the header file for a class that was automatically created in your project. This class is where you implement your app UI and logic. The  Application class contains the main event loop for your app, which handles all interactions between the user and your app (for example, touch events or button clicks). The Application class also handles the app's initialization and finalization.  QLocale and  QTranslator are Qt classes that are used for handling localized strings. The last include is a class that is used to enable your app for debugging and profiling.

You can learn about debugging and profiling in Build, test, and deploy your app.

#include "applicationui.hpp"

#include <bb/cascades/Application>
#include <QLocale>
#include <QTranslator>

#include <Qt/qdeclarativedebug.h>

The next line is a declaration for using the bb::cascades namespace. By using the namespace, the app can call bb::cascades functions without having to specify the bb::cascades namespace each time.

using namespace bb::cascades;

The next line is the function definition for main(). This function runs when a Cascades app starts.

Q_DECL_EXPORT int main(int argc, char **argv)
{

Inside the body for main(), an Application object is created.

Application app(argc, argv); 

Next, we create an instance of our ApplicationUI class (the class created with your project for app UI and logic). In the next part of the tutorial, we see how this class is used to import a QML file containing the app's UI.

ApplicationUI appui;

The last thing we do is tell Application to start its event loop. When the event loop ends (for example, when a user closes the app), the Application deletes the scene and all of its children, and cleans up app resources.

return Application::exec();

Load a QML file into your app

Now that you've seen how an app is started, let's have a look at how to load a QML file into it. In the src folder, double-click the applicationui.cpp file located in your project.

#include "applicationui.hpp"

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

using namespace bb::cascades;

ApplicationUI::ApplicationUI() :
        QObject()
{
    // prepare the localization
    m_pTranslator = new QTranslator(this);
    m_pLocaleHandler = new LocaleHandler(this);

    bool res = QObject::connect(m_pLocaleHandler, 
        SIGNAL(systemLanguageChanged()), 
        this, 
        SLOT(onSystemLanguageChanged()));

    // This is only available in Debug builds
    Q_ASSERT(res);
    // Since the variable is not used in the app, 
    // this is added to avoid a compiler warning.
    Q_UNUSED(res);

    // initial load
    onSystemLanguageChanged();

    // Create scene document from main.qml asset, the parent is set
    // to ensure the document gets destroyed properly at shut down.
    QmlDocument *qml = 
        QmlDocument::create("asset:///main.qml").parent(this);

    // Create root object for the UI
    AbstractPane *root = qml->createRootObject<AbstractPane>();

    // Set created root object as the application scene
    Application::instance()->setScene(root);
}

void ApplicationUI::onSystemLanguageChanged()
{
    QCoreApplication::instance()->removeTranslator(m_pTranslator);
    // Initiate, load and install the application translation files.
    QString locale_string = QLocale().name();
    QString file_name = QString("MyFirstApp_%1").arg(locale_string);
    if (m_pTranslator->load(file_name, "app/native/qm")) {
        QCoreApplication::instance()
            ->installTranslator(m_pTranslator);
    }
}

At the top of the file, the required header files and classes are included. After the include statements, there's a using directive for the bb::cascades namespace. This directive allows the app to use all the classes in bb::cascades without specifying the namespace on each instance.

#include "applicationui.hpp"

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

using namespace bb::cascades;

In the constructor for ApplicationUI, we set up the localization of our content before we create any of the app's UI. We create a QTranslator object to handle localization of any text output in our app and a LocaleHandler to listen for changes to the locale of the device that is running our app. We also connect the systemLanguageChanged() signal to a slot that we define in our main.cpp.

ApplicationUI::ApplicationUI() :
        QObject()
{
    // prepare the localization
    m_pTranslator = new QTranslator(this);
    m_pLocaleHandler = new LocaleHandler(this);

    bool res = QObject::connect(m_pLocaleHandler, 
        SIGNAL(systemLanguageChanged()), 
        this, 
        SLOT(onSystemLanguageChanged()));

    // This is only available in Debug builds
    Q_ASSERT(res);
    // Since the variable is not used in the app, 
    // this is added to avoid a compiler warning.
    Q_UNUSED(res);

    // initial load
    onSystemLanguageChanged();
;

Next in the constructor for ApplicationUI, we call the QObject constructor to set the parent of app. This approach ensures that when the app stops running, the ApplicationUI object is deleted. Next, a QmlDocument object is created using the main.qml file located in the project's assets folder. Then, we set the parent of the QmlDocument object to this app. The QmlDocument object represents a QML file that is loaded into your app.

// Create scene document from main.qml asset, the parent is set
// to ensure the document gets destroyed properly at shut down.
QmlDocument *qml = 
    QmlDocument::create("asset:///main.qml").parent(this);

And finally, the root object is retrieved from the QmlDocument object. The root object must be a subclass of AbstractPane and is used to set the scene for the app.

    // Create root object for the UI
    AbstractPane *root = qml->createRootObject<AbstractPane>();

    // Set created root object as the application scene
    Application::instance()->setScene(root);
}

That's our constructor completed. We still have to define that slot that we connected to the systemLanguageChanged() signal. This slot removes any existing translators attached to your app, finds the current country and language of the device running your app, and installs a translator for the new locale.

void ApplicationUI::onSystemLanguageChanged()
{
    QCoreApplication::instance()->removeTranslator(m_pTranslator);
    // Initiate, load and install the application translation files.
    QString locale_string = QLocale().name();
    QString file_name = QString("MyFirstApp_%1").arg(locale_string);
    if (m_pTranslator->load(file_name, "app/native/qm")) {
        QCoreApplication::instance()
            ->installTranslator(m_pTranslator);
    }
}

If you look at your applicationui.hpp file, you can see all of the declarations that you need to use these classes as well as two private global declarations for the QTranslator and LocaleHandler that your app uses. You won't usually have to change these classes or declarations.

If you would like to learn more, you can check out Internationalization.

#ifndef ApplicationUI_HPP_
#define ApplicationUI_HPP_

#include <QObject>

namespace bb
{
    namespace cascades
    {
        class LocaleHandler;
    }
}

class QTranslator;

/*!
 * @brief Application UI object
 *
 * Use this object to create and init app UI, 
 * to create context objects, to register the 
 * new meta types etc.
 */
class ApplicationUI : public QObject
{
    Q_OBJECT
public:
    ApplicationUI();
    virtual ~ApplicationUI() {}
private slots:
    void onSystemLanguageChanged();
private:
    QTranslator* m_pTranslator;
    bb::cascades::LocaleHandler* m_pLocaleHandler;
};

#endif /* ApplicationUI_HPP_ */

Now that we've seen how an app is started and how the QML is loaded, let's get to the good stuff: creating your UI using QML!

If you'd like to skip the QML part of the tutorial, you can jump ahead to the last part of the tutorial and Create your UI with C++.

Last modified: 2015-03-31



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus