Qt Reference Documentation

Page Based Application Navigation on Symbian

Qt Quick Components provides two methods for application navigation. The PageStack system provides a way of navigating a hierarchy of pages. It is a stack that you can push pages of content onto and pop pages off the stack. The page at the top of the stack is what the user sees. The other method is to create pages in tabs. With the tabs system, the pages are arranged in a tab and the user can select the pages by clicking on the tabs.

Page Component

A Page component serves as a container for other QML content. A page may contain additional components such as a TextEdit or Button components.

A Page may be created by defining the page inline or by encapsulating it in a Component element. Inline definitions of pages are ideal for small pages, however, all of the pages will remain in memory during creation. To exert control over the creation and destruction of a page, encapsulate them in a Component element.

Alternatively, a page can be defined in its own .qml file. This makes it easier to locate the source for each page and maintain the pages. It also makes it easier to share page implementations between applications.

Attaching a Tool Bar to a Page

You can integrate the PageStack with the ToolBar. This allows the pages to use the same instance of the ToolBar and run synchronized animations with the push and pop operations. This integration happens at the root level of your application, usually in the Window.

 PageStack {
     id: pageStack
     toolBar: commonToolBar
     anchors { left: parent.left; right: parent.right; top: parent.top; bottom: toolBar.top }
 }

 ToolBar {
     id: commonToolBar
     anchors.bottom: parent.bottom
 }

The snippet above creates a PageStack and a ToolBar. The toolBar property of the PageStack binds to the created toolbar. This property binding allows the PageStack to update the application level ToolBar instance automatically when it changes the active Page.

Because the ToolBar instance is already created, the only thing left for the Page is to define the content - this is done by populating the tools property of the Page.

In the snippet below, a ToolBarLayout is used to position the ToolButton components.

 Page {
     id: firstPage
     tools: ToolBarLayout {
         id: pageSpecificTools
         ToolButton { iconSource: "toolbar-back"; onClicked: Qt.quit() }
         ToolButton { text: "next page"; onClicked: pageStack.push(secondPage) }
     }
 }

The tools content is re-parented to the ToolBar instance when the page is shown.

Hierarchical Navigation with a PageStack

Pushing a page to the stack will make the page visible to the user. The stack can store many pages and to navigate back, the stack can pop pages. The stack can replace the top page with a different page (or pages) rather than popping and pushing pages. In all these cases, the page stack performs appropriate transition animations to help the user understand a change is occurring.

Pushing Pages to the Stack

There are basically three ways you can push a page onto the stack:

  1. File: Pass a file name (URL) for a page defined in a QML file: For example: pageStack.push(Qt.resolvedUrl("FilePage.qml")). The stack then simply loads the page from the file.
  2. Item reference: Pass a reference to the item that defines the page. For example, pageStack.push(myPage), where myPage is an instantiated object.
  3. Component reference: Pass a reference to a component that defines a page, such as a declaration encapsulated in a Component element. The stack then creates a new instance of that component.

Encapsulating page definitions in a Component element means you can defer their creation and memory does not need to be allocated until the page is needed. Further, the page stack instantiates the page and destroys the instance when the page is popped from the stack. This means you don't have to worry about memory management since it is all handled by the page stack. As well, pages as components allow multiple instances of a particular page type to be at the stack. This means you can define one component with configurable variations rather than defining a separate item for each variation.

Page Navigation with ToolBars

The ToolBar instance can be used for page navigation.

 Page {
     id: firstPage
     tools: ToolBarLayout {
         id: pageSpecificTools
         ToolButton { iconSource: "toolbar-back"; onClicked: Qt.quit() }
         ToolButton { text: "next page"; onClicked: pageStack.push(secondPage) }
     }
 }
 Page {
     id: secondPage
     tools: ToolBarLayout {
         ToolButton { iconSource: "toolbar-back"; onClicked: pageStack.pop() }
     }
 }

The ToolButton can be bound to the PageStack commands such as push and pop. This way the page navigation can be made more intuitive for the end user.

Blocking User Actions During Page Transitions

The PageStack's busy property evaluates to true when the stack is changing pages. The busy property is useful for notifying the application when the stack changes to prevent unintentional events or user input.

 MouseArea {
     anchors.fill: parent
     enabled: pageStack.busy
 }

Binding this property can disable mouse interaction within a MouseArea.

Page Navigation with Tabs

Alternatively, the Tab component can contain Page items. The parallel arrangement of pages are managed by the tab and clicking on a tab switches the visible pages.

The buttons are implemented with the TabButton component. You can layout these buttons as you like. In the ToolBar, the ButtonRow is used for laying. This also changes the buttons graphical presentation to match the ToolBar's look and feel.

 ToolBarLayout {
     ToolButton {...} // back button
     ButtonRow {
         TabButton {...}
         TabButton {...}
 }

You can use TabBarLayout, and TabBar in Symbian, to layout buttons for a stand-alone tool bar. In this case, the you must position the TabBarLayout.

 TabBarLayout {
     anchors.top: parent.top
     width: parent.width
     TabButton {...}
     TabButton {...}
 }

The tab content is managed by the TabGroup component whose child items are content items.

 TabGroup {
     anchors {...} // user needs to layout the tab group
     Page { id: tab1Content }
     Page { id: tab2Content }
 }

The button and the content items are linked together with the TabButton's tab property.

 TabButton { id: tab1Button; tab: tab1Content }

Once the linking is established, the TabButton and TabGroup components manage the tab content switching and also highlight the corresponding tab button.

Dynamic Tab Handling

In most cases, the tab count is static. Therefore, you can statically allocate child items of TabGroup and the layouting component as described above. In some cases, you have to add or remove tabs dynamically depending on the application state.

You can append a tab by creating a new TabButton as a child of the layout and similarly creating a new content item as the TabGroup's child. In addition, you need to set the TabButton's tab property to point to the new content item.

If you need to re-arrange the tab buttons, you need to clear the layout and append the buttons again in the correct order. The item order in the TabGroup does not affect the shown tab order.

You can remove a tab by deleting TabButton and the content item instances with destroy().

Improving Performance

Use Qt.createComponent() to load the pages only when you need a page, use Component.createObject() to parse the page and create an instance of it. Note that normal property bindings cannot be used because you are using a component, rather than a specific QML object. To get around this, you need to specify a map of properties and values when the component is instantiated. See Dynamic Object Management in QML for more details.