Fundamentals of Cascades
The Cascades framework lets you create UIs for the BlackBerry Application Platform with relative ease. Cascades is based on Qt 4.8, which is an application framework that uses C++. Many fundamental principles of Qt apply to Cascades as well, so it's important to understand a few key ideas to be able to work with Cascades effectively. For more information about the Qt framework, see qt-project.org/doc/qt-4.8/.
Application lifecycle
All Cascades applications have a similar lifecycle, which includes three possible states: running in the foreground, running in the background, and stopped.
- An app is running in the foreground if it is currently visible and uses the entire screen.
- An app is running in the background if it's visible and is running as an active frame, such as when a user swipes up from the bottom of the bezel to display a list of running apps. An app is also considered to be running in the background if it's not visible but has the appropriate permissions to run in the background (you'll learn about these permissions in the next section).
- An app is stopped if it's not visible and doesn't have permission to run in the background.

Allowing your app to run in the background
Some apps that you develop interact directly with users while the app is running. For example, your app might display a UI and let a user interact with it. However, you can develop another app that doesn't require user input while the app is running. This type of app might listen for a particular event to occur on the device and then respond by notifying the user at that time. You might want this type of app to run in the background until it needs to alert the user that the event occurred.
By default, your apps won't run if they're in the background and aren't visible. Processor time isn't allocated to apps that are in this state, and this approach helps to minimize battery power consumption and maximize the performance of the device. To allow an app to continue running while it's not visible, you need to specify the run_when_backgrounded permission in your project's bar-descriptor.xml file.
<permission>run_when_backgrounded</permission>
When an app doesn't have permission to run in the background, the application lifecycle includes the Stopped state. An app enters this state when it's in the background and not visible. The app can't perform any operations in this state.
When an app has permission to run in the background, there is no Stopped state. The app continues to run when it's in the background and not visible, and the app can continue to perform operations and process events in this state.
Managing application states
To help you keep track of which state your application is in, the Application class includes several signals that are emitted when the state changes. Here are a few of the most important signals for these state changes:
This signal is emitted when the app is brought to the foreground and uses the entire screen. In this state, the app can use all of the resources that it requires (for example, the app isn't limited to a specific amount of memory or processor time).
When your app is in this state, you can assume that the user is viewing your app and actively interacting with it.
This signal is emitted when the app is sent to the background and becomes an active frame. By default, the active frame image (also called the cover) that's displayed is a scaled-down version of what the app's UI looked like when it was sent to the background. You can change the cover by using the AbstractCover class and its subclasses, along with the Application::setCover() function.
When your app is in this state, it should stop any extraneous processing and use only the resources it needs to update the cover. Your app should stop other threads, such as networking and data access threads, that aren't required when running in the background.
This signal is emitted when the app (and its active frame) are no longer visible. The app might enter this state if the device backlight is off or if another app is brought to the foreground.
When your app is in this state and doesn't have permission to run in the background, it is stopped and won't receive any processing time. If your app has permission to run in the background, your app should stop any rendering operations (for example, updating the UI) and any other unnecessary operations. Your app should listen only for the events that it needs to respond to and process these events when they occur.
Closing your application
When a user closes your app, you might want to perform some final clean-up operations before the app closes. For example, you can save the user's data, shut down your threads in a particular way, or close database or network connections manually. The Application class includes several functions and signals that you can use to detect the termination of your app and delay it long enough to perform any final tasks your app needs.
This function sets the value of the autoExit property, which indicates whether your app should close automatically or should receive a signal when a user closes your app. If you set this property to false using this function, your app receives the manualExit() signal (described below) when a user closes your app. You should remember that if you set the autoExit property to false, you must call quit() to terminate the app when you finish any final clean-up operations.
This signal is emitted if the autoExit property is set to false by calling setAutoExit(). Your app can respond to this signal and perform any clean-up operations that are required before closing. After this signal is emitted, your app has a short amount of time (approximately three seconds) to perform any final tasks and terminate itself before the operating system terminates it forcibly. You can request more time to complete your tasks by calling extendTerminationTimeout().
This function requests additional time to perform clean-up operations before your app is terminated forcibly. When you call this function, your app has about two seconds to finish its tasks and terminate itself. Note that calling this function doesn't add two seconds to the existing timeout period. Instead, it resets the timeout period to two seconds from the time this function is called. You can call this function as many times as you need to extend the timeout period.
QML and C++
Qt Modeling Language (QML) is a declarative language that's based on JavaScript and is included as part of Qt. It was developed as a simple but powerful language for developers to use for creating UIs. You can use QML to describe the structure and behavior of a set of UI controls. QML uses concepts such as objects, properties, and signals and slots to let objects communicate with each other. For more information about QML and how it's used in Qt, see qt-project.org/doc/qt-4.8/qdeclarativeintroduction.html.
Cascades uses a modified version of QML to let you create UIs for your apps. You can start by using a set of core UI controls that's provided for you; this is the easiest and fastest way to create your first few Cascades apps. When you're more familiar with the framework, you can add functionality to create animations, handle touch events, apply text styles, and more. You can even create your own custom controls for the look and feel you want.
Here's an example of a simple Cascades UI that's defined in QML. This app consists of several UI controls: a Page, Container, Button, and Label. To learn more about these controls and others that you can use, take a look at Creating User Interfaces.
import bb.cascades 1.0
Page {
Container {
Button {
text: "Click me!"
}
Label {
text: "Here's a simple text label."
}
}
}
QML makes it easy to identify the relationships between the various components in an app. In the code sample above, the Button and Label both belong to the Container, which itself belongs to the Page. QML lets you quickly see how controls are related to each other and how they might be laid out visually in your app. The idea of one control belonging to another control (that is, being owned by another control) is important when object ownership is discussed later.
Here's another important idea: almost anything you can do in QML, you can do in C++. Each Cascades control is represented by an underlying C++ class. For most properties of QML controls, such as the text property in the code sample above, there are associated C++ functions that you can use to retrieve or set the values of these properties. Here's the C++ code that's equivalent to the QML code sample above:
// Create the root page and top-level container
Page *root = new Page;
Container *topContainer = new Container;
// Create the button
Button *myButton = new Button;
myButton->setText("Click me!");
// Create the label
Label *myLabel = new Label;
myLabel->setText("Here's a simple text label.");
// Add the button and label to the container
topContainer->add(myButton);
topContainer->add(myLabel);
// Set the content of the page
root->setContent(topContainer);
To see an example of how to create an app using QML and C++, see Create your first app.
So, when should I use QML and when should I use C++?
You can use either QML or C++ to write your apps. You can even combine both languages in the same app. However, even if you choose to write your app entirely in QML, there's still some C++ code that you need to include to load the QML and get the app started. Don't worry, this C++ code is provided for you when you create a new Cascades project in the QNX Momentics IDE. To learn more about how to combine QML and C++ in your apps, see C++ and QML integration.
In general, you should consider using QML to define the look and feel of your app. You can use predefined UI controls, such as buttons, text fields, labels, sliders, and drop-down menus, and you can respond to user interaction such as button clicks. Use different layouts to arrange these controls, or even create your own custom controls and add them to your layouts. With QML, you can create visual designs and test them quicker than with C++.
You should consider using C++ for the business logic of your app. You can create your own C++ classes and use them to perform calculations, handle data storage operations, and so on. You can use the full capabilities of C++ to supplement the UI-related features that QML provides.
By using QML for your UI and C++ for your business logic, you can change one aspect without affecting the other. For example, you can change the appearance of a list of items without worrying about how the data for the list is stored or accessed. Or, you can implement a new sorting algorithm in your app without affecting how the data is shown to users on the screen.
QObject, the Qt base class
All objects in Cascades are derived from the QObject class. This class is the base class of all Qt objects and provides several important features. Most notably, QObject provides support for signals and slots, which is a powerful mechanism that allows objects to communicate with each other. When something happens to an object in your app (for example, a user clicks a button), the object emits a signal. You can handle that signal and respond to the event by using a function called a slot. To learn more about signals and slots in Cascades, see Signals and slots.
To learn more about QObject in Qt, see qt-project.org/doc/qt-4.8/qobject.html.
This section provides information about the structure of a QObject subclass by examining parts of a C++ header file. This information is important if you want to understand the connection between QML elements (such as properties) and their C++ equivalents. This information is also important if you create your own components and want to use them with other QObject elements.
You don't need to rely on C++ to create your own controls; you can create flexible, reusable UI controls using QML too. To learn how, see Custom QML components.
To illustrate some of the features and requirements of a QObject in Cascades, consider the Button control. This control represents a clickable button that you can use in your apps. The header file (button.h) for this control is located in the folder where you installed the BlackBerry 10 Native SDK, in the target\qnx6\usr\include\bb\cascades\controls subfolder. Let's take a closer look at some of the code in this file and what the code means.
Class declaration
class QT_CASCADES_EXPORT Button : public AbstractButton {
All Cascades controls inherit QObject, either directly or indirectly. The Button class inherits several intermediate classes, all of which eventually inherit QObject.
Q_OBJECT macro
private:
Q_OBJECT
To identify a class as a QObject, you need to use the Q_OBJECT macro in the private: section of the class definition. This macro is processed by the Qt meta-object compiler (MOC) and enables features such as properties, signals, and slots. To learn more about the Qt meta-object system and meta-object compiler, see qt-project.org/doc/qt-4.8/metaobjects.html.
Property declaration
Q_PROPERTY(QString text READ text WRITE setText RESET resetText
NOTIFY textChanged FINAL)
A property is a single piece of information about an object, and is declared by using the Q_PROPERTY macro. This macro allows the property to be accessible in QML. In the Q_PROPERTY, you specify the name and type of the property. You also use keywords (such as READ and WRITE) to specify the names of functions to manipulate the property value. Properties are declared in the private: section of the header file, along with the Q_OBJECT macro.
As you can see above, the Button class includes the text property, which specifies the text that appears on the button. This property is a QString (the Qt representation of a text string) and has functions called text(), setText(), and resetText() to get, set, and reset the value of the property, respectively. These functions still need to be declared later; the Q_PROPERTY macro only associates them with the property. You can also specify a signal that's emitted when the value changes by using the keyword NOTIFY. To learn more about properties and the keywords you can use, see qt-project.org/doc/qt-4.8/properties.html.
Function declaration
public:
Q_SLOT void setText(const QString & text);
You can create functions for QObject classes just as you do for any other C++ classes. Notice, though, that the Q_SLOT macro is used before the function declaration here. This macro is another special element of Qt and indicates that this function is a slot. You can connect slots to signals so that when a signal is emitted, the connected slot function is called automatically. As an alternative to the Q_SLOT macro, you might see slot functions declared in a public slots: section in a header file. In Cascades, these approaches are identical.
Another useful macro that you might see is Q_INVOKABLE. You can use this macro in front of a function declaration (in the same place as Q_SLOT above) to indicate that you want to be able to call the function from QML. This approach can be useful if you have a complicated operation (for example, a custom transition for your UI control) that you want to implement in C++. You can still keep the UI-related portion (calling the function at the appropriate time) in QML, but you can implement the operation in C++ any way you want. To learn more about Q_INVOKABLE, see C++ and QML integration.
Signal declaration
Q_SIGNALS:
void textChanged(QString text);
You can use the Q_SIGNALS: section to declare signals that a QObject emits when certain events occur. A Button emits the textChanged() signal when its text changes, and you can handle this event in your app if you need to. You might also see signals declared in a signals: section in a header file, which means the same thing in Cascades.
Object ownership
Every QObject can be related to other objects in parent/child relationships. An object can have one parent, as well as zero or more children. A parent object owns its child objects. When an object is destroyed, its children are also destroyed, so it's important to remember which objects are related to other objects in your apps.
Scene graphs
Cascades maintains the relationships between objects internally, and transfers ownership between objects automatically when you call functions that change object ownership. To make it easier to visualize the parent/child relationships in your app, you can use a hierarchichal structure called a scene graph. This graph shows the controls (also called nodes) in your app and how they're related to each other. You can't view the scene graph for your app in the QNX Momentics IDE or anywhere else; it's just a concept that makes it easier to visualize how Cascades keeps track of object relationships internally.
A hierarchical structure (such as a scene graph) is commonly used in many types of applications, such as complex UI applications and games, and makes it easier to manage complex arrangements of components. Using a hierarchichal structure can also increase the performance of applications, which is a major reason why it was chosen as a feature for Cascades. Finally, the hierarchical nature of scene graphs fits nicely with the parent/child relationship structure of Qt objects. To learn more about this relationship structure, see qt-project.org/doc/qt-4.8/objecttrees.html.
For example, consider a Container with two Button controls.
Container {
Button {
text: "Button 1"
}
Button {
text: "Button 2"
}
}
Here's what the scene graph would look like for this arrangement:

Scene graphs can help you keep track of how object ownership might affect various aspects of your app. For example, you can use a scene graph to visualize how touch events are delivered to different controls on the screen. To learn how scene graphs can help you handle touch events, see Touch propagation.
Object ownership in QML
In QML, object ownership is established automatically according to the structure of the QML code that you write. For example, consider the following code sample that creates two Button controls and adds them to a Container:
Container {
Button {
text: "Button 1"
}
Button {
text: "Button 2"
}
}
The container is the parent of the buttons, and the buttons are children of the container. When the container is destroyed, both buttons are destroyed as well.
Object ownership in C++
In C++, object ownership is a bit more complicated. Initial object ownership can be established either when controls are created or when they're added to other controls. Both approaches result in the same parent/child relationships, so you can choose which approach you prefer to use in your apps.
For example, here's how to create the same container and buttons from the QML code sample above. This approach establishes object ownership when the buttons are created. The parent for each button is specified in the Button constructor, and each button becomes owned by the specified parent automatically when it's created.
// Create the top-level container Container *topContainer = new Container; // Create the buttons, specifying the container as the parent. The container now // owns the buttons. Button *buttonOne = new Button(topContainer); Button *buttonTwo = new Button(topContainer);
Here's a second approach that establishes object ownership by adding the buttons to the container explicitly.
// Create the top-level container Container *topContainer = new Container; // Create the buttons Button *buttonOne = new Button; Button *buttonTwo = new Button; // Add the buttons to the container. The container now owns the buttons. topContainer->add(buttonOne); topContainer->add(buttonTwo);
After object ownership is established, you can change the parent of an object by adding the object to a different parent. The object is removed from the first parent and added to the new parent, and the new parent then owns the object. Here's an example:
// Create two containers Container *firstContainer = new Container; Container *secondContainer = new Container; // Create a button Button *myButton = new Button; // Add the button to the first container. The first container now owns the // button. firstContainer->add(myButton); // Add the button to the second container. The second container now owns the // button, and the first container no longer owns it. secondContainer->add(myButton);
You can also remove an object from a container without specifying a new parent for the object. However, this is when things get tricky: even though the object was removed from the container, the container is still the object's parent and still owns the object. If the container is deleted, the object is deleted as well.
This behavior can lead to errors in your application that might be difficult to recognize. For example, consider the following example of two buttons that are added to a container. The second button is then removed from the container, and after the button is removed, the container is deleted. Finally, the removed button's setText() function is called.
// WARNING: This code will generate an error if you try to run it.
// Create a container
Container *myContainer = new Container;
// Create two buttons and add them to the container
Button *buttonOne = new Button;
Button *buttonTwo = new Button;
myContainer->add(buttonOne);
myContainer->add(buttonTwo);
// Remove the second button from the container
myContainer->remove(buttonTwo);
// Delete the container
delete myContainer;
// Attempt to set the text of the removed button
buttonTwo->setText("Button Two");
Because the second button was removed from the container before the container was deleted, you might expect that when the container is deleted, the button isn't deleted and you can still access it. However, the container remains the parent of the button even after remove() is called. The second button is deleted when the container is deleted (along with the first button), so the call to setText() isn't valid because the button doesn't exist anymore.
When an object is removed from its parent, or when an object is replaced by a new object (in the case of certain setter functions, such as Page::setContent()), it's removed from the visual hierarchy (that is, it's not displayed on the screen anymore). The object's parent still owns the object, but you can change the parent or delete the object at this point. If you don't change the object's parent, it's still deleted when the parent object is deleted. It's important to note that you can't change the parent of an object if the object is still part of the visual hierarchy of its parent. You need to remove it before you try to change its parent.

All QObject instances include a function called setParent(), and you can use this function to change the parent of an object (when it's allowed, as described above). When you use setParent() to change an object's parent, the function doesn't add that object to the parent's visual hierarchy; you still need to add it explicitly (for example, by calling Container::add()).
To prevent the error that occurred in the code sample above, you can add a call to setParent(0) after you remove an object from its parent. This way, the object isn't deleted when its former parent is deleted.
...
// Remove the button from the container
myContainer->remove(buttonTwo);
// Reparent the button so that it's not deleted when the container is deleted
buttonTwo->setParent(0);
// Delete the container
delete myContainer;
// Attempt to set the text of the button. This time, this call will work as
// expected because the button hasn't been deleted. You'd still need to add
// the button to the visual hierarchy of another container (using add()) for
// the button to appear on the screen.
buttonTwo->setText("Button Two");
There's one important exception to the rules of object ownership. The top-level scene in your application, which is the AbstractPane object that you set as the root node using Application::setScene(), behaves differently. The application takes ownership of this AbstractPane only if the pane doesn't already have a parent. If the AbstractPane doesn't have a parent when setScene() is called, the application owns the pane and deletes it if a new scene is set. However, if the AbstractPane already has a parent, the application won't take ownership of the pane when setScene() is called.
This behavior lets you switch between different scenes in your applications but ensures that for the most basic use case (an application with just a single scene), the old scene is deleted when appropriate. If you want to switch between two scenes, you should set the parents of the AbstractPane objects explicitly using setParent() before you call setScene().
Many other functions of Cascades classes change the ownership of objects. You should check the API reference for the classes and functions that you're working with to make sure that they don't change object ownership in unexpected ways.
Thread support
Qt provides support for threaded applications with the QThread class. The ability to create new threads is often necessary if your application contains resource-intensive processes that might otherwise block the UI thread. A QThread represents a separate thread of control in the application; it can share data with all the other threads within the application, but runs independently in the same way that a standalone application does. To facilitate communication between threads, signals and slots are fully supported.
Previously, the standard method for creating a QThread was by subclassing it. Now, you should use QThread by creating a worker object that is derived from QObject and implementing a slot on that worker to handle the task. The worker should also specify a signal that is emitted when the task is finished, and an optional signal that is emitted when there's an error.
class Worker : public QObject {
Q_OBJECT
public:
Worker();
virtual ~Worker();
public slots:
void process();
signals:
void finished();
void error(QString err);
};
After you create the worker class, you can give QThread ownership of the worker, connect the appropriate signals and slots, and start the thread.
// Create a thread QThread* thread = new QThread; Worker* worker = new Worker(); // Give QThread ownership of Worker Object worker->moveToThread(thread); // Connect worker error signal to this errorHandler SLOT connect(worker, SIGNAL(error(QString)), this, SLOT(errorHandler(QString))); // Connects the thread's started() signal to the process() slot in the worker, // causing it to start connect(thread, SIGNAL(started()), worker, SLOT(process())); // Connect worker finished signal to trigger thread quit, then delete connect(worker, SIGNAL(finished()), thread, SLOT(quit())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); // Make sure the thread object is deleted after execution has finished connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start();
Using C APIs in your Cascades applications
The BlackBerry 10 Native SDK includes all of the Cascades APIs, which you can use to create responsive UIs that follow the same visual style as the core BlackBerry 10 apps (such as the Calendar application and Contacts application). However, the SDK also includes many other native C APIs (also known as core native APIs) that you can use when you develop your apps. These core native APIs are designed to make it easier to port existing apps to the BlackBerry Application Platform, but you can use these APIs in your Cascades apps if you want. To learn the distinction between core native APIs and Cascades APIs, visit http://developer.blackberry.com/platforms/ndk/.
The Cascades and C++ APIs provide most of the functionality that you need to create your apps. The Cascades APIs provide UI-related features, and the C++ APIs give you access to underlying device features and services, such as networking, sensors, Payment Service, and so on. However, there are some features that are available only by using core native APIs. You can learn more about these APIs and the features they provide by visiting the documentation page at http://developer.blackberry.com/native/documentation/bb10.
Here's a list of some of the features that are available only by using core native APIs:
Audio Manager
The Audio Manager APIs provide advanced audio features, such as automatic and manual routing, audio stream-type identification, concurrency policy management, and audio device monitoring.
For more information, visit the multimedia documentation.
Scoreloop
The Scoreloop SDK contains APIs that let you integrate social gaming features into your apps. You can use Scoreloop APIs to provide features such as leaderboards, challenges, and awards and achievements.
For more information, visit the Scoreloop documentation.
Cryptography
The BlackBerry 10 Native SDK includes C APIs that support cryptographic features, such as symmetric and asymmetric encryption, key agreement and transport, digital signatures, hash functions, and random number generation.
For more information, visit the security documentation.
Last modified: 2013-03-21