BlackBerry: Comeback mit neuer Ausrichtung

Seite 2: Qt, QML und Cascades

Inhaltsverzeichnis

Wer Anwendungen für Unix erstellt, kennt sicherlich das Cross-Plattform-Framework Qt. BlackBerry setzt voll auf dessen JavaScript-basierte Sprache QML und erweitert die Sprache sogar noch um einen vom neuen Qt-Maintainer Digia nicht standardisierten Dialekt namens Cascades. Er ermöglicht wunderbar aussehende Effekte samt Animationen und ist für die Realisierung der kompletten Benutzerschnittstelle des Betriebssystems verantwortlich. Interessant ist, dass Cascades komplett "bilingual" aufgebaut ist. Es ist also (theoretisch) möglich, eine Cascades-Anwendung ausschließlich in C++ zu realisieren.

Weitaus häufiger ist der Einsatz im "Kombinationsmodus". Dabei realisieren Entwickler die Benutzerschnittstelle in Cascades, die Geschäftslogik entsteht hingegen in C++. Diese Struktur hat mehrere Vorteile, die insbesondere in komplexeren Workflows mit mehreren Entwicklern und Grafikern zu Tage treten. Die strenge Aufteilung zwischen Logik und Benutzerschnittstelle ermöglicht es, dass die beiden Teams parallel arbeiten. Änderungen in der GUI lassen sich ohne Meldung an das Entwicklerteam realisieren – zumindest dann, wenn eine gewisse Übereinkunft über die Benennung der Steuerelemente besteht. Der Grund dafür liegt im Signal-Slot-System von Qt, das Cascades aus der QML-Implementierung übernimmt.

Da das erstmalige Einrichten einer Signal-Slot-Verbindung für Einsteiger schwierig ist, zeigt der Artikel die ersten Schritte. Dazu ist ein neues Projektskelett für eine Cascades-Applikation zu erstellen und der QML-Quellcode von main.qml folgendermaßen zu adaptieren:

// Default empty project template
import bb.cascades 1.0

// creates one page with a label
Page {
signal aButtonClicked()
Container {
layout: DockLayout {}
Label
{
objectName: "txtTestText"
verticalAlignment: VerticalAlignment.Top
horizontalAlignment: HorizontalAlignment.Center
text: "Test-Text"
}
Button
{
id: cmdChangeText
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Center
text: "Text ändern!"
onClicked:
{
aButtonClicked();
}
}
}
}

Mehrere Stellen sind wichtig. Erstens deklariert der Entwickler alle zu sendenden Signale als erste Eigenschaft des Root-Objekts. Das ist wichtig, da sie sonst nicht beim Empfänger ankommen. Der Container enthält die eigentlichen Steuerelemente. Das Label wird aus dem C++-Code heraus angesprochen und bekommt deshalb einen Objektnamen zugewiesen. Der Button hat die Aufgabe, das Signal auszugeben. Deshalb weist der Entwickler der onClicked-Eigenschaft eine Funktion zu, die die Emission des Signals durchführt.

Übrigens ist Cascades in der Lage, beliebige JavaScript-Funktionen auszuführen. Es wäre also möglich, die hier in C++ realisierte Änderung des Label-Texts direkt in JavaScript umzusetzen.

Im Header des C++-Objekts erstellt man einen Slot und eine neue Member-Variable:

class HeiseSample2 : public QObject
{
Q_OBJECT
public:
HeiseSample2(bb::cascades::Application *app);
virtual ~HeiseSample2() {};

public slots:
void handleButtonClick();

private:
QObject* myObject;
};

Im Konstruktor des Objekts wird der sogleich besprochene Slot durch das Aufrufen der Connect-Methode mit dem vom QML-Dokument emittierten Signal verdrahtet. Außerdem ist findChild aufzurufen, um einen Pointer auf das Label zu erhalten.

HeiseSample2::HeiseSample2(bb::cascades::Application *app)
: QObject(app)
{
// create scene document from main.qml asset
// set parent to created document to ensure it exists for the
// whole application lifetime
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 a scene
app->setScene(root);
connect(root, SIGNAL(aButtonClicked()), this, SLOT(handleButtonClick()));

QString myName="txtTestText";
myObject=root->findChild<QObject*>(myName);
if(myObject==NULL)
{
myName="abc";

}
}

Im Slot wird setProperty aufgerufen, die Texteigenschaft des Labels anzupassen:

void HeiseSample2::handleButtonClick()
{
myObject->setProperty("text", "Hallo Welt!");
}

Damit ist das Programm ausführbereit. Die Abbildung 1 zeigt es in Aktion.

Die Textänderung funktioniert (Abb. 1).

In der Vergangenheit gab es keine klare Aussage von RIM zur Verfügbarkeit von Qt-Widgets. BlackBerry 10 enthält nun eine voll funktionsfähige Implementierung der von Symbian und MeeGo bekannten Widgets. Beim Einsatz der QtGui-Bibliothek gilt es, eine wichtige (und in der Dokumentation nicht besprochene) Besonderheit der Qt-Implementierung zu beachten. Die Basisklassen bb::application und bb::cascades::application können keine QtGui nutzende Widgets hosten. Stattdessen ist der gesamte Einsprungpunkt des Cascades-Projektskeletts nach folgendem Schema zu ersetzen:

Q_DECL_EXPORT int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QtMainWindow w;
w.showFullScreen();

return a.exec();
}

Auf der Basis baut man den Rest der Anwendung nach dem von Qt unter Symbian gewohnten Schema auf. Auch die Struktur der .pro-Datei ist identisch – der User Interface Compiler (uic) ist Teil des Frameworks.

Die Formulare sehen durchaus brauchbar aus (s. Abb. 2 und 3), erreichen aber nicht das Look & Feel nativer Steuerelemente.

Die Buttons erinnern stark an Cascades-Applikationen (Abb. 2).

Leider hört die Ähnlichkeit schon bei den Checkboxen auf (Abb. 3).

Eine wesentliche Verbesserung der Darstellung lässt sich durch das Aktivieren des BB10-Style Plug-ins erreichen – die auf der BlackBerry Jam enstandene Abbildung 4 zeigt die Vorgehensweise, den zu verwendenden Code und die erreichbaren Resultate. Aufgrund der verschiedenen Renderingpfade schließt das Verwenden von QApplication (und/oder von normalem QML) den Einsatz von Cascades-Komponenten aus. Das hat zur Konsequenz, dass die Anwendungen unter Umständen nicht zum "Built For Blackberry"-Programm (dazu später mehr) zugelassen werden.

Vorgehensweise, den zu verwendenden Code und die erreichbaren Resultate durch Aktivieren des BB10-Style-Plugins (Abb. 4)