Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

How to build a tabbed UI with QML

From Wiki
Jump to: navigation, search
Article Metadata
Code ExampleCompatibility
Platform(s):
Symbian
Article
Created: jappit (18 Feb 2011)
Last edited: hamishwillee (30 Jan 2013)

This article shows how to build a tabbed User Interface by using QML. A tabbed UI shows a tab bar on the lower part of the screen, containing one or more tabs: each tab, once clicked by the user, shows a different view on the upper part of the UI.

Wiki n8 qml tabbedui.png

Contents

The base structure

Start by creating an empty QML file, called TabbedUI.qml: this file will contain the component.

The base structure of this component can be composed of two different parts: an upper Rectangle, that will contain the views associated to each tab, and a lower Rectangle (the tab bar), that will contain the tabs. The component also defines two properties:

  • tabsHeight: defines the height of the tab bar
  • tabIndex: defines the index of the currently selected tab

A gradient is added to the tab bar, in order

Rectangle {
// height of the tab bar
property int tabsHeight : 64
 
// index of the active tab
property int tabIndex : 0
 
anchors.fill: parent
 
// will contain the tab views
Rectangle {
id: tabViewContainer
width: parent.width
 
anchors.top: parent.top
anchors.bottom: tabBar.top
}
 
// the tab bar
Rectangle {
height: tabsHeight
width: parent.width
 
// take the whole parent width
anchors.left: parent.left
anchors.right: parent.right
 
// attach it to the view bottom
anchors.bottom: parent.bottom
 
id: tabBar
 
gradient: Gradient {
GradientStop {position: 0.0; color: "#666666"}
GradientStop {position: 1.0; color: "#000000"}
}
}
}

The Model

In order to populate the TabbedUI, a Model will be used: specifically, the component will use a VisualItemModel, where each visual item represents the view associated to each tab. Each visual item will be a Tab object, as defined below:

Rectangle {
// name of the tab
property string name
 
// icon to be displayed in the tab
property string icon
 
anchors.fill: parent
}

The Tab component simply extends the Rectangle object, and defines two properties that are used to create the tab on the TabbedUI's tab bar:

  • name: the name of the tab
  • icon: the icon displayed within the tab

By using a VisualItemModel and the Tab component, a model for the TabbedUI, containing 3 tabs, can be defined as follows:

VisualItemModel {
id: tabsModel
Tab {
name: "Tab 1"
icon: "pics/tab0.png"
 
color: "yellow"
Text {
anchors.centerIn: parent
text: "This is page 1"
}
}
Tab {
name: "Tab 2"
icon: "pics/tab1.png"
 
color: "green"
Text {
anchors.centerIn: parent
text: "This is page 2"
}
}
Tab {
name: "Tab 3"
icon: "pics/tab2.png"
 
color: "red"
Text {
anchors.centerIn: parent
text: "This is page 3"
}
}
}

Using the VisualItemModel

Let's take back the TabbedUI component, and add a new property that will hold the model:

Rectangle {
 
[...]
 
// the model used to build the tabs
property VisualItemModel tabsModel
 
[...]
 
}

Now, the tabViewContainer Rectangle can be populated by using a Repeater together with the provided model, as follows.

Rectangle {
id: tabViewContainer
width: parent.width
 
anchors.top: parent.top
anchors.bottom: tabBar.top
 
// build all the tab views
Repeater {
model: tabsModel
}
}

Similarly, the tab bar can be built with a Repeater. Since tabs have to be placed on a row, a Row positioner is added to the tabBar Rectangle:

// the tab bar
Rectangle {
id: tabBar
 
[...]
 
// place all the tabs in a row
Row {
anchors.fill: parent
 
id: tabs
}
}


To populate the Row added to the tab bar, let's define a Component that will be used as delegate to build a single tab bar Item.

This component is automatically sized depending on the number of items in the tabsModel, and is composed of:

  • An Image object holding the tab icon
  • A Text object holding the tab name
  • A MouseArea that intercepts the mouse events and calls a tabClicked() function, that will be defined later
Component {
id: tabBarItem
 
Rectangle {
height: tabs.height
width: tabs.width / tabsModel.count
 
color: "transparent"
 
Image {
source: tabsModel.children[index].icon
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 4
}
 
Text {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
color: "white"
text: tabsModel.children[index].name
}
 
MouseArea {
anchors.fill: parent
onClicked: {
tabClicked(index);
}
}
}
}

Now, the tabs Row can be populated by using a Repeater as follows:

// the tab bar
Rectangle {
id: tabBar
 
[...]
 
// place all the tabs in a row
Row {
anchors.fill: parent
 
id: tabs
 
Repeater {
model: tabsModel.count
 
delegate: tabBarItem
}
}
}

Selecting tabs

Now that we have the static component, some behavior needs to be added. When the user clicks on a tab, the Component must:

  • highlight the clicked tab, and unselect the previous tab
  • show the associated tab view, and hide the previously shown tab view

In order to to this a tabClicked() JavaScript function is defined:

function tabClicked(index)
{
// unselect the currently selected tab
tabs.children[tabIndex].color = "transparent";
 
// hide the currently selected tab view
tabsModel.children[tabIndex].visible = false;
 
// change the current tab index
tabIndex = index;
 
// highlight the new tab
tabs.children[tabIndex].color = "#30ffffff";
 
// show the new tab view
tabsModel.children[tabIndex].visible = true;
}

Component startup

When the component has been completely initialized, the default tab has to be selected. The Component.onCompleted signal can be used for this purpose:

Component.onCompleted:
{
// hide all the tab views
for(var i = 0; i < tabsModel.children.length; i++)
{
tabsModel.children[i].visible = false;
}
// select the default tab index
tabClicked(tabIndex);
}

Using the TabbedUI component

The TabbedUI component can be used as shown in the following code snippet:

Rectangle {
width: 360
height: 640
 
id: root
 
VisualItemModel {
id: tabsModel
Tab {
name: "Tab 1"
icon: "pics/tab0.png"
 
color: "yellow"
Text {
anchors.centerIn: parent
text: "This is page 1"
}
}
Tab {
name: "Tab 2"
icon: "pics/tab1.png"
 
color: "green"
Text {
anchors.centerIn: parent
text: "This is page 2"
}
}
Tab {
name: "Tab 3"
icon: "pics/tab2.png"
 
color: "red"
Text {
anchors.centerIn: parent
text: "This is page 3"
}
}
}
 
TabbedUI {
tabsHeight: 72
tabIndex: 1
tabsModel: tabsModel
}
}

The above code can be seen in action in the following video.

The media player is loading...

Related content

A Qt Creator project containing the source code presented in this article is available here: File:TabbedQuickApp.zip

A Symbian^3 installation file is also available here: File:Tabbedquickapp qt-4 7 0 exp m1 1 0 s3 v0 9.zip


QML Elements

Reference docs of the main QML Elements used in this article are available here: Rectangle, Text, Gradient, GradientStop, VisualItemModel, Component, MouseArea, Row, Image

This page was last modified on 30 January 2013, at 04:29.
852 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×