Contents |
This tutorial will demonstrate a simple (but non-trivial) app which uses
This tutorial assumes you have the MeeGo SDK installed on Linux
See: http://wiki.meego.com/SDK/Docs/1.2/MeeGo_SDK_1.2_Preview
Also assumed: you have a a chroot / Xephyr environment set up.
This tutorial will use meego-ux-components objects like:
For other uses of Meego UX Components, and another tutorial of Book Menus, See:
Other QML Tutorials:
qtcreator &>/dev/null &
... screen shots ...
import QtQuick 1.0
Rectangle {
width: 360
height: 360
Text {
text: "Hello World"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
}
(CTRL-R or Green "Play" Button) ====
<screen shot>
Clicking it closes the app (Qt.quit())
import Qt 4.7
import MeeGo.Components 0.1
Window {
id: window
bookMenuModel: [ qsTr("Button Demo"), qsTr("Book 2") ]
bookMenuPayload: [ gallery, book2 ]
bookMenuTitle: qsTr("Book Menu")
Component.onCompleted: switchBook( gallery )
//Component { id: gallery; MainPage {} }
//Component { id: book2; Book2 {} }
}
Run the app and see the Book Menu. If you click on one of the menu items, you'll notice an error because of the commented out Component statements.
Adding the Book2 Component (from the meego-ux-widgetgallery example) (right click on the QML folder in the Projects view and Add New... / QML File / "Book2.qml")
Replace the generated file Book2.qml with this:
/*
* Copyright 2011 Intel Corporation.
*
* This program is licensed under the terms and conditions of the
* LGPL, version 2.1. The full text of the LGPL Licence is at
* http://www.gnu.org/licenses/lgpl.html
*/
/* This file contains relativy empty pages and is meant to demonstrate the
book/page concept */
import Qt 4.7
PageDummy {
id: pageDummy
innerText: qsTr("book 2, page 1")
rectColor: "lightblue"
showButton: true
buttonLabel: qsTr("Page 2")
pageTitle: qsTr("Dummy book 2")
onClicked: { addPage( page2 ) }
Component{
id: page2;
PageDummy {
id: pageDummy2
innerText: qsTr("book 2, page 2")
rectColor: "lightgreen"
showButton: true
buttonLabel: qsTr("Page 3")
pageTitle: qsTr("Dummy book 2")
onClicked: { addPage( page3 )
}
}
}
Component{
id: page3;
PageDummy {
id: pageDummy3
innerText: qsTr("book 2, page 3")
rectColor: "orange"
showButton: true
buttonLabel: qsTr("Page 4")
pageTitle: qsTr("Dummy book 2")
onClicked: { addPage( page4 )
}
}
}
Component{
id: page4;
PageDummy {
id: pageDummy4
innerText: qsTr("book 2, page 4")
rectColor: "darkgrey"
pageTitle: qsTr("Dummy book 2")
}
}
}
The file Book2.qml references PageDummy.qml, so create it:
/*
* Copyright 2011 Intel Corporation.
*
* This program is licensed under the terms and conditions of the
* LGPL, version 2.1. The full text of the LGPL Licence is at
* http://www.gnu.org/licenses/lgpl.html
*/
/* This file is just meant as a dummy to quickly create pages for
demonstrating the book/page concept. */
import Qt 4.7
import MeeGo.Components 0.1
AppPage {
id: pageDummy
property alias innerText: rectText.text //text shown in the rect
property alias rectColor: innerRect.color //color of the rect in the middle
property alias showButton: nextButton.visible //nextButton visible?
property alias buttonLabel: nextButton.text //nextButton label
property string bookTitle: "book title" //shown in the title bar
signal clicked()
anchors.fill: parent
Rectangle { z: -1; anchors.fill: parent; color: "grey" } //background
Rectangle {
id: innerRect
anchors.fill: parent
anchors.margins: 50
color: "lightgreen"
Text {
id: rectText
text: "dummy page"
anchors.centerIn: parent
font.pixelSize: 40
color: "black"
}
}
Button {
id: nextButton
visible: false
text: "next page >"
anchors.right: innerRect.right
anchors.bottom: innerRect.bottom
anchors.margins: 10
onClicked: { pageDummy.clicked() }
}
}
You will see the use of the meego-ux-components "Button" and "AppPage" components in PageDummy.qml
Now, replace the two commented out Component statements in main.qml with:
Component {
id: gallery;
AppPage {id: dummy2}
}
// Dummy page until MainPage.qml is defined
AppPage { id: gallery; }
//Component { id: gallery; MainPage {} }
Component { id: book2; Book2 {} }
Since the MainPage.qml file isn't created yet, use a dummy AppPage placeholder temprarily to prevent a run-time error when invoking the menu.
You can now click on the Book2 menu and see a new page.
Continue with the Tutorial for seeing custom List Views in the MainPage...
Now, we're going to create a Component called MainPage.qml which will display a custom ListView:
We will use a C++ QAbstractListModel to repersent out list.
Create the file mymodel.h by right-clicking on the simple-app project name and "Add New..." a C++ Header File
Paste this into mymodel.h
#ifndef MYMODEL_H
#define MYMODEL_H
#include <QAbstractListModel>
#include <QColor>
struct Data {
Data( const char* name, const QString& flag, double population )
: name(name), flag(flag), population(population) {}
QString name;
QString flag;
double population;
};
const int FlagRole = Qt::UserRole + 1;
const int PopulationRole = Qt::UserRole + 2;
class MyModel : public QAbstractListModel
{
public:
MyModel();
int rowCount( const QModelIndex& ) const;
QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
QList< Data > m_data;
};
#endif // MYMODEL_H
Create the mymodel.cpp file with this content:
#include "mymodel.h"
#include <QByteArray>
MyModel::MyModel()
{
m_data
<< Data("Denmark", "qrc:images/denmark.jpg", 5.4)
<< Data("Sweden", "qrc:images/sweden.jpg", 9.3)
<< Data("Iceland", "qrc:images/iceland.jpg", 3.2)
<< Data("Norway", "qrc:images/norway.jpg", 4.8)
<< Data("Finland", "qrc:images/finland.jpg", 5.3);
// By default the DisplayRole is mapped to the propery "display"
QHash<int, QByteArray> mapping =roleNames();
mapping.insert( FlagRole, "flag");
mapping.insert( PopulationRole, "population");
setRoleNames( mapping );
}
int MyModel::rowCount( const QModelIndex& ) const
{
return m_data.count();
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
if ( !index.isValid() )
return QVariant();
Data data = m_data[index.row()];
if ( role == Qt::DisplayRole )
return data.name;
else if ( role == FlagRole )
return data.flag;
else if ( role == PopulationRole )
return data.population;
else
return QVariant();
}
Modify main.cpp by replacing its contents with this:
#include <QtGui/QApplication>
#include <QDeclarativeEngine>
#include <QDeclarativeContext>
#include "qmlapplicationviewer.h"
#include "mymodel.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyModel model;
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/simple-app/main.qml"));
viewer.showExpanded();
// Register the model "myModel" with QML
QDeclarativeContext *context = viewer.engine()->rootContext();
context->setContextProperty("myModel", &model);
return app.exec();
}
Now, add the file MainPage.qml
/*
* Copyright 2011 Intel Corporation.
*
* This program is licensed under the terms and conditions of the
* LGPL, version 2.1. The full text of the LGPL Licence is at
* http://www.gnu.org/licenses/lgpl.html
*/
/* The MainPage lets the user switch between different contents which
show the widgets available in these components. */
//import Qt 4.7
import QtQuick 1.0
import MeeGo.Components 0.1
AppPage {
id: mainPage
// This will be the first app / content displayed in the Button Demo page
state: "flags"
pageTitle: qsTr("Button Demo")
// Demo an Action Menu......
// Comment the block below to see a new Action Menu
// actionMenuModel: [ qsTr("Landscape"),
// qsTr("Portrait"),
// qsTr("Inv. Landscape"),
// qsTr("Inv. Portrait") ]
// actionMenuPayload: [ 1, 2, 3, 4 ]
// actionMenuTitle: qsTr("Action Menu")
// onActionMenuTriggered: {
// if( selectedItem == 1) {
// window.orientation = 1
// } else if( selectedItem == 2) {
// window.orientation = 2
// } else if( selectedItem == 3) {
// window.orientation = 3
// } else if( selectedItem == 4) {
// window.orientation = 0
// }
// }
Item {
id: contentButtons
// Some Debug output to stderr ...
onVisibleChanged: {
console.log("xxxxxxxxxxxxxx 1 Parent wid ", parent.width);
console.log("xxxxxxxxxxxxxx 2 Wid ", width);
}
onWidthChanged: {
console.log("wwwwwwwwwwwwww 1 Parent wid ", parent.width);
console.log("wwwwwwwwwwwwww 2 Wid ", width);
}
property int buttonWidth: parent.width * 0.2;
property int buttonHeight: 60;
property int buttonMargins: 2;
property string activeButtonImage: "image://themedimage/widgets/common/button/button-default"
property string buttonImage: "image://themedimage/widgets/common/button/button"
property string buttonImagePressed: "image://themedimage/widgets/common/button/button-default-pressed"
//width: 2 * buttonWidth + 3 * buttonMargins
height: buttonHeight
anchors.top: parent.top
anchors.topMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
Button {
id: flagsButton
active: true
width: parent.buttonWidth; height: parent.buttonHeight
// Since there are only two buttons, the right of this button is near the center.
anchors { margins: parent.buttonMargins; right: parent.horizontalCenter;}
text: qsTr("Flags")
onClicked: {
mainPage.state = "flags"
active = true
browserButton.active = false
}
}
Button {
id: browserButton
width: parent.buttonWidth; height: parent.buttonHeight
// This button is to the right of the flags button
anchors { margins: parent.buttonMargins; left: flagsButton.right }
text: qsTr("File Browser")
onClicked: {
mainPage.state = "browser"
active = true
flagsButton.active = false
}
}
}
// This item holds the contents of the selected button and fills the rest of the window
Item {
id: contentSpace
anchors { top: contentButtons.bottom; bottom: parent.bottom; left: parent.left; right: parent.right }
}
// One of these two components will fill the contentSpace Item above.
FlagContent { id: flagContent; anchors.fill: contentSpace; anchors.top: contentButtons.bottom }
//Placeholder until BrowserContent.qml is present
Rectangle { id: browserContent; anchors.fill: contentSpace; anchors.top: contentButtons.bottom; color: "red"; }
//BrowserContent { id: browserContent; anchors.fill: contentSpace }
Rectangle { z: -1; anchors.fill: parent; color: "grey" } //background
states: [
State {
name: "flags"
PropertyChanges { target: flagContent; visible: true }
PropertyChanges { target: browserContent; visible: false }
},
State {
name: "browser"
PropertyChanges { target: flagContent; visible: false }
PropertyChanges { target: browserContent; visible: true }
}
]
}
Add the File FlagContent.qml...
This shows an example of using a QML ListView - which uses a delegate for a row to be displayed
import QtQuick 1.0
ListView {
clip: true
model: myModel
anchors.top: parent.bottom
anchors.fill: parent
delegate: Rectangle {
color: Qt.rgba(0.9,0.9,0.9)
height: childrenRect.height
width: parent.width
Image {
id: image
source: flag
width: 64
height: 64
fillMode: Image.PreserveAspectFit
anchors { left:parent.left; leftMargin:30}
}
Text {
text: display + "\n" +"population: " + population + " mill."
anchors { left:image.right; verticalCenter: image.verticalCenter; leftMargin: 5 }
}
}
}
Modify main.qml to remove this:
AppPage { id: gallery; }
Uncomment this line:
Component { id: gallery; MainPage {} }
Since we added new .cpp and .h files, it would be a good idea to Build->Run Qmake; Build->Rebuild All
Copy the images and .qrc file from the solution directory:
Add this to your simple-app.pro RESOURCES += resources.qrc
Rebuild...
Run...
To see another mini-app for the "Browser" button, copy these files to your project from the solution directory:
BrowserContent.qml FileSystemView.qml ImageViewer.qml PathDisplay.qml dirmodel.cpp dirmodel.h main.cpp (new code added to register a Directory Model with QML named "_model"
Replace these two lines in MainPage.qml:
Rectangle { id: browserContent; anchors.fill: contentSpace; anchors.top: contentButtons.bottom; color: "red"; }
//BrowserContent { id: browserContent; anchors.fill: contentSpace }
With...
BrowserContent { id: browserContent; anchors.fill: contentSpace }
Rebuild All
Run