-work in progress-



this article is work-in-progress



This is part 8 of a series of  apps helping you to understand Qt 5.7 for x-platform development on Android and iOS. This app is not a Demo App – it’s a real life APP I developed for QtCon 2016 in Berlin. Please read the blogs about my other Examples to understand the concepts and patterns I’m using:

  1. First app with One Page
  2. StackView
  3. SwipeView
  4. TabBar
  5. Bottom Navigation
  6. Drawer Navigation
  7. Business Data APP

Download QtCon 2016 Conference App

The App is available at Google Play Store for Android Devices and from Apple Apptore for iPhones. Also work has started to provide a Windows 10 Mobile App.


You don’t have a Google Account and want to side-load the App ? Here’s the APK – Download – Link.



Out of the Developer Trenches

This blog will give you some insights and explain some parts of the code.

I’ll also speak at Qt World Summit about my experiences while developing this app and show what happens behind the scenes.

Here’s a short overview what I’m using to create the UI of my Qt 5.7 – QtQuickControls2 Business Apps:


There are also StackViews on top of a single Page from SwipeView:

Conference Schedule is a SwipeView, each Day is a Page with ListView for all Sessions of the Day. From the List you can open SessionDetailPage (pushing on Stack) and so on.

Drawer and Bottom Bar Navigation

Main Navigation is done by a Drawer.


Now Google Material Style also supports Bottom Navigation I added a Bottom Navigation Bar to make it easier to navigate. To get the Drawer opened you must swipe from the left site or tap on the Menu Button on Top Left. The Menu Button on Top Left isn’t always visible: if pushing Pages on a Stack, the Button is replaced by a Back Arrow to navigate back – so in this case you must use the gesture from left side. Not so easy if you have a large display size or like to use your phone with one hand. The Bottom Navigation Bar enables you to go through the Pages faster without moving fingers a long distance.


There are buttons for Home, Schedule, Speaker and Tracks inside the Bottom Navigation Bar. You can reach these Buttons easy. There’s also a Menu Button (Hamburger) at Bottom Left position. This Button is always visible, which means you can easy switch between different parts of the App even if there are some Pages on the Stack.

The Bottom Navigation Bar is only visible in Portrait Mode – in Landscape it would eat too much space from available height.

Now there are two Hamburger Menus in Portrait and perhaps you don’t like to have the Menu Button at the bottom ?

No problem – you can customize this. GoTo Settings and select the way you like to navigate.

  • Classic Material Navigation Style ( only the Drawer is used to navigate)
  • Bottom Navigation (Bottom Navigation Bar without Menu Button in Portrait)
  • Comfort (One Hand Use) Navigation (Menu Button in Bottom Navigation Bar)
  • Use only One Menu Button (In Portrait there’s no Menu Button in Title Bar, only in Bottom Navigation

I implemented these options to demonstrate how easy it is to customize your QuickControls2 Apps.

BTW: Coming from BlackBerry 10 Cascades ? Then you already know about the Menu Button at Bottom left. So using Bottom Navigation with Menu Button there could also help to get same Navigation Workflow on different platforms. Will help you if developing Enterprise Business Apps as I’m doing.

Speed Stack Navigation

Sometimes you pushed some Pages on top of a StackView. per ex. Schedule -> Session Detail -> Speaker Detail -> Room Info.

To push Pages on stack you tapped on Buttons to navigate “forward” to the next detail you’r interested in.

To go back to the Schedule – Sessions List you must tap on the Back Button multiple times. On Android you can also use the OS Back Button at Bottom Left, but on iOS you always have to move your finger to Top Left Back Button.

To speed up this kind of Navigation I implemented “Speed Stack Navigation”: the FAB (Floating Action Button) is used to navigate back: with one Tap you jump back to the last used List below. The FAB is always at Bottom Right position so always reachable even with one-hand-use.

Here’s an example from Session Details Page:


Themes and Colors

From Settings page you can also customize the Colors and dark / light theme:


here are screenshots using a dark theme:



Dynamic Loading

There are many StackViews, SwipeViews, Pages, ListViews …

To provide a performant App it’s a good think to think about dynamic creation of Components. QtCon Conference App uses many Loaders. A Loader is only a placeholder and you must set the ‘active’ property to start Object creation.

Inspired by BlackBerry 10 Cascades TabbedPane delegateActivationPolicy I have implemented different Activation Policies:

  • Immediately
  • Lazy
  • When Active

Immediately means that the Loader is active from beginning and will remain until the end. This is used for HomePage – the first page a user will see.

Lazy means the first time a user wants to see this Page, the Loader will become active and then wil remain.

When Active means the Loader will only be active as long as the Page is in use. Closing the page will set the Loader to inactive and the Controls will be destroyed.

But that’s not the complete story – to speed up the Startup Time I’m doing it this way:

C++ classes like DataManager, DataServer, DataUtil are only created at startup – no init() is done – so it’s really fast.

In QML no Drawer and Bottom Navigation is created, because I don’t set a model. The initial Item of the root StackView (used by Drawer) is a special Page only containing a Busy Indicator:


As soon as this initial Page is created I start a Timer with 300 ms delay and from the Timer I’m calling all the C++ init() methods, all the data was read from cache and if all is done I’m setting the Drawer model. Now the Pages with Immediate – Activation – Policy are created and I’m swapping the initial Page and the Home Page is visible to the user.

In most cases the Busy Indicator will only be visible for some ms.

Caching and Data Binding

For this App I’m using a JSON File Cache.

A Conference App displays Sessions, Speaker, Rooms and this kind of data was read from Cache and QObject* are created – so the complete data was in-memory for fast access.

This data wasn’t changed from normal app – use. The only data a user enters is setting favorite Sessions to create the Personal Schedule. To avoid saving all the Sessions, I’m using an extra Class to store the ID’s of Sessions marked as Favorite. Caching this as JSON will only write a File with some Bytes.

At startup I’m looping through the Favorites and set a Property for these Sessions, so in Lists and Pages I’m getting the Favorite info directly from Session Class. This Property is a transient Property for Sessions.

Closing the App or sending to background I’m looping through the Sessions and create the Favorites. Then this small file was written to cache.

Using QObject* DataBinding to QML UI is easy – most difficult part is creating all the code for Q_PROPERTY. This is done by a Code Generator – all these C++ Classes you’ll find under src/gen. This Code Generator is based on Eclipse Xtext and I’m generating different Code for BlackBerry10 / Qt 4.8 and Qt 5.7 Android/iOS. The CodeGenerator will be Open Source – expect this by the end of 2016.

Caching and Data Binding is a complex story – will blog in an extra article about this.


Find some more Screenshots from the Conference App below.

Some Screenshots are outdated – per ex. the Icons to swap between Personal Schedule and Conference Schedule were changed because of Beta testers Feedback.

Stay tuned for more blog articles and videos explaining patterns and concepts.

There’s an Option Menu available at Startpage. All these Options are also part of the Drawer, but to help users first time using a Drawer I placed this Options Menu to get easy access to Help and Settings.


QtCon Conference App works in Portrait and Landscape. There are some situations where rotating back from Landscape to Portrait doesn’t work as expected. Will report this and more via Bugreports.


Conference Schedule is a SwipeView with pages for each Conference Day. The List of Sessions of a Day can be long, so there’s a ‘GoTo’ Button to jump to a specific Time Slot.


TimePicker is a customized UI Control I created with some help from Mitch Curtis.

Use this TimePicker to jump to Sessions starting at a specific time:


Personal Schedule (lists only marked Sessions). Easy toggling between Personal and Conference Schedule


Session Details:


Room Floorplan – you can Zoom-In / Zoom-Out or Fit-To-Window:


List of Speakers:


GoTo Speaker where Name starts with a specific Letter:


Speaker details


List of Tracks – in the meantime Tracks are colored to match UI from Web Browser.


Sessions per Track


Venue Info


Venue Rooms List. Tap on a Room to see all Sessions or on the Thumbnail to see the Floorplan.


Sessions per Room


Help Page


About Page




This Application is Open Source and available at Github: https://github.com/ekke/c2gQtCon


As a good Open Source Project Citizen I always report Bugs and Requests.

Here are some of the Bugs I ran into while developing this APP:



I’m waiting for Feedback from QtCon in Berlin to see what could be done better.

Next Conference App will be for Qt World Summit 2016 in San Francisco.

My personal wishlist for upcoming Qt Conference Apps:

  • Integration with Twitter, Browser, Map
  • Having Bookmarks and Favorites
  • Personal Schedule Collision Detection
  • From Session –> what’s running at Same Time
  • Fulltext Search for Sessions and Speakers
  • Update from Conference Schedule via Push
  • Update Info (what’s new, removed, timeslots-rooms changed …
  • Better Highlighting of List rows
  • List of Sponsors
  • Shortcuts for BlackBerry PRIV
  • Jump to NOW while Conference running
  • Remove short Flicker at Android Startup
  • Pinch && Zoom Overview as I did for Cascades
  • TimePicker with AM PM support
  • TimePicker better resizing small screens
  • Translate into more languages
  • Support of Android Tablets and iPads

Stay tuned for more Apps – next one will be for Qt World Summit 2016 in San Francisco.


← Back (Business Data APP)

→ Next Article (Qt World Summit Conference APP-TBD-)

⇐ Home (Overview / Topics)

Business Data App

July 14, 2016 — Leave a comment

Work in Progress – wait for Tweet @ekkescorner


This is part 7 of a series of demo apps helping you to understand Qt 5.7 for x-platform development on Android and iOS. This app demonstrates some aspects of a Business App. Please read the blogs abvout my other Examples before:

  1. First app with One Page
  2. StackView
  3. SwipeView
  4. TabBar
  5. Bottom Navigation
  6. Drawer Navigation





as usual at Github: https://github.com/ekke/biz_data_x


You learned ….xxxxxxx

Stay tuned for the next Example Apps …

← Back (Drawer Navigation App)

→ Next Article (Qt Con Conference APP)

⇐ Home (Overview / Topics)


This is part 6 of a series of demo apps helping you to understand Qt 5.7 for x-platform development on Android and iOS. This app demonstrates using a Drawer to navigate and contains some concepts explained before. Please read the blogs abvout my other Examples before:

  1. First app with One Page
  2. StackView
  3. SwipeView
  4. TabBar
  5. Bottom Navigation

Bottom Navigation is good for Apps with 3 – 5 different areas. If your app covers more aspects, then a Drawer is the way to go. Read at Google Material Style Guide about Drawer Navigation and take a look at Qt documentation on Drawer – a Navigation Control from Qt Quick Controls 2.

I tried to implement different functionality into the Drawer:

  • Header with Logo and Text
  • Items with Icon + Text
  • Items with Text-only (typically About, Help, Info)
  • Dividers to separate different areas
  • Subtitles
  • Showing a Counter (per ex. Number of emails, Orders, …)
  • Showing a colored Marker
  • Highlighting current Selection

See this Screenshot:


As you know, I’m developing crossplatform Business Apps for BlackBerry10, Android, iOS. One of the most important requirements is a fast and smooth workflow through an App which includes short ways for the fingers to tap on buttons. To open a Drawer there are two ways:

  • Swipe from the left site to see the destinations
  • Tap on Menu Button (top-left)


Both actions are not easy for one-hand-use. That’s why I liked the introduction of Bottom Navigation by Google. HowTo use this with Qt 5.7 we talked about in my previous example app.

Why not combining both ? Drawer and Bottom Navigation ? From Settings you can switch Bottom Navigation for Favorites on:


As you can see I set Home, Car, Flight, Settings as ‘Favorite Destinations’. In this example app this decision was made fix – in a real life app the user should select favorites. Please note, that the left most Button is the Menu Button to open the Drawer.

Now it’s easy to open most-used Buttons or the Drawer from Menu at Bottom Navigation.

Favorites as Bottom Navigation will only be there if APP is in Portrait Mode.

Coming from BlackBerry 10 Cascades ? This looks similar to TabbedPane, where Tabs are shown on ActionBar. Makes it easy to have consistant workflow x-platform.

From Settings you also can Hide the TitleBar and decide if active selection should be highlighted.

Navigation Model

Items in Drawer and Buttons in Bottom Navigation are drawn by Repeater from Navigation Model, which is an array of:

	{ "type": "../navigation/DrawerNavigationButton.qml", 
	"name": "Home", 
	"icon": "home.png", 
	"source": "../navigation/HomeNavigation.qml", 

‘type’ can be:

  • DrawerNavigationButton.qml
  • DrawerDivider.qml
  • DrawerSubtitle.qml

‘name’, ‘icon’, ‘source’ are used to generate NavigationButtons

‘showCounter’, ‘showMarker’ adds this behavior to a NavigationButton

‘a_p’ means activationPolicy

From this NavigationModel the Drawer can be created easy. If Bottom navigation is in-use, same Model is used from a mapping:

property var favoritesModel: [
        0, 3, 7, 9

Be Dynamic (ActivationPolicy)

Coming from BlackBerry10 Cascades ? TabbedPane is similar to Drawer and TabbedPane has a TabDelegateActivationPolicy for dynamic loading of Tabs. I implemented similar policies for Draqwer Navigation.

I’m using Loaders to create Destinations. There are three Activation Policies:

  • LAZY

IMMEDIATELY: .active = true for the Loader, so the Item was always loaded at the beginning and stays loaded.

LAZY: .active = false for the Loader. First time the Item inside the Loader  will be used, activate is set to true and will stay true. LAZY is good for performance at the beginning and will be used for items user normaly will access meny times.

WHILE_CURRENT: .active = false for the Loader. .active will only set to true WHILE the Item is the currentItem. If user switches to another node, the Loader will set .active = false. Next time same node is used, Item will created again. This option is good for memory-hungry complex Pages, the User normaly only will use seldom. Attention: As soon as the Item was unloaded, you lost your state. If you want to remember last sate, you must store the values anywhere.

For this Example APP here are the Activation Policies used to demonstrate how it’s done:

  • IMMEDIATELY: Home Page, Flight Page
  • LAZY: Car, Bus, Truck, Color Schema Pages
  • WHILE_CURRENT: Subway Page, Settings, About

Starting the App, all Destinations will be created from Repeater:

Repeater {
    id: destinations
    model: navigationModel
    // Destination encapsulates Loader
    // depends from activationPolicy how to load dynamically
    Destination {
	id: destinationLoader
    Component.onCompleted: {
	// all destinations (Loader) created
	// all destinatation items w activationPolicy IMMEDIATELY activated
	// now show first destination (should always be IMMEDIATELY)

All marked as IMMEDIATELY will become active and loaded. When all is done, the first one will replace the initial item on StackView. Drawer is using a StackView where the root Item always will be replaced by the Item selected from Drawer or Bottom Navigation. In a real life App perhaps it could take some time before all is created, so there’s an InitialItemPage showing a BusyIndicator.


Chances are great that you never will see this Page from Example App, because it’s only a demo app with less logic or data-loading behind.

Here’s the Destination.qml (Loader):

Loader {
    id: pageLoader
    property int pageActivationPolicy: modelData.a_p
    active: pageActivationPolicy == activationPolicy.IMMEDIATELY
    visible: false
    source: modelData.source
    onLoaded: {
        if(pageActivationPolicy != activationPolicy.IMMEDIATELY) {

There are two functions – activateDestinations() and replaceDestination() – managing the load / unload and refresh() on StackView. You can study this from sources.

Pages, StackView, SwipeView / TabBar

It depends from your use-cases what happens if User selects a destination. You can use a Page if there’s only one Page needed to show the content. You can use a StackView with TabBar and/or PageIndicator to provide sub-navigation as done for the ColorSchema where you can swipe through 3 Pages to select Primary Color, Accent Color and Theme or you can use a StackView.

The concept is the same as already described in Bottom Navigation APP – Activation Policies are first time used here in this App.

If using some nodes with StackViews where the User wants to jump between and expects to get the same leaf, don’t use Activation Policy WHILE_SELECTED.

Take a look at the sources to see How I implemented all this stuff. As in previous Examples there’s a init() function and cleanup() function to simulate some biz logic.

Coming from BlackBerry10 Cascades ? Here’s (from a 4-years-old Blog😉 How a typical Cascades App can be structured:


Compare this with a Qt 5.7 App designed with Material Style for Android and iOS as done for this Example, you’ll recognize a similar architecture. This is great for x-platform app development and why I prefer to use Qt 5.7 for Android / iOS Apps: much stuff from C++ is same, Event handling using SIGNAL / SLOT is similar and also UI Architecture as we have seen now.



Providing same Workflow for mobile Business Apps for all target Platforms is important – esp. in Enterprise.


as usual at Github: https://github.com/ekke/drawer_nav_x


You learned HowTo use Qt Quick Controls 2 to implement Drawer Navigation.

Stay tuned for the next Example Apps …

← Back (Bottom Navigation App)

→ Next Article (Business Data App)

⇐ Home (Overview / Topics)



This is part 5 of a series of demo apps helping you to understand Qt 5.7 for x-platform development on Android and iOS.

You should have read the blogs about my first app using Qt 5.7 Material Style, my second app (StackView Example) the third app (SwipeView Example) and 4th app (Tab Bar Example) before reading on.

All the navigation through your APP was done using a single root object:

  • Page
  • StackView
  • SwipeView
  • TabBar (with SwipeView)

What if an app will become more complex, where you need some tabs at root, where each tab can itself point to a Page, StackView, SwipeView or TabBar ?

For a long time there was only the Drawer sliding in from the left side. (per ex. used by Google Play APP)

Fortunately Google just introduced a new navigation component: Bottom Navigation. Bottom Navigation uses a ToolBar at the bottom with minimum 3 Buttons and maximum 5 Buttons. You only have two areas ? Use a TabBar, you have more then 5 areas ? Use a Drawer.

There’s a ToolBar with ToolButtons as part of new Qt Quick Controls 2, but no Bottom Navigation Bar. Don’t panic ! It’s easy to customize Qt Quick Controls to have your own Bottom Navigation Control.

Coming from BlackBerry10 Cascades ? TabbedPane  is similar to the Drawer. Having only some Tabs, you can set showTabsOnActionBar: true to get a Bottom Navigation. Coming from iOS ? A Bottom Navigation Bar is used as the default navigation, so it could be the way for x-platform development with Bottom Navigation if 5 Buttons are enough.

You should have installed Qt 5.7 RC.

New to Qt 5 development ? Please read my blog series from the beginning to learn some basic stuff and to understand this app.

From Google Material Style Guide you know that there are many ways to style the Navigation Bar. I have tried to implement all these ways in this example APP. Here’s a screenshot using a (with Primary Color) colored Bottom Bar, where Buttons have white or black Icons. (Depends from Primary Color: Open Options Menu and select Yellow as primary Color: all Icons will become black)



Notice that the inactive Buttons are dimmed.

Having 4 or 5 Buttons, only the active Button will show the Label, having 3 Buttons will always show the Label where the Fontsize for inactive Buttons is smaller.


On iOS most APPs don’t colorize the Bottom Navigation Bar, you can configure this:


Without using a Primary Color Background where Icons are white, now the active Button is colored with Primary Color, inactive are black or white (depends from Theme) with reduced Opacity.

Settings and Toast (Popups)

Tapping on the FAB (Floating Action Button) a Popup with some Settings appears:


Try out the different configurations. How this kind of stuff works, I already have explained in previous Example APPs.

Settings uses ‘OK’ as default action – even if you tap outside the Popup to close. It’s up to you how you’ll implement such behavior – depends from use-case or customer requirements. One of my Enterprise customers has the requirement, that all Popups, Dialogs, … have a default key which will be executed if closed or auto-closed after a specified timeout. So I wanted to try out this, too and implemented a ‘Toast‘. Toast is used in Android to let the user know that something happened and Toast is closed automatically.

here’s the source /popups/PopupToast.qml:

Popup {
    id: popup
    closePolicy: Popup.NoAutoClose
    bottomMargin: isLandscape? 24 : 80
    x: (appWindow.width - width) / 2
    y: (appWindow.height - height)
    background: Rectangle{
        color: toastColor
        radius: 24
        opacity: toastOpacity
    Timer {
        id: toastTimer
        interval: 3000
        repeat: false
        onTriggered: {
    } // toastTimer
    Label {
        id: toastLabel
        leftPadding: 16
        rightPadding: 16
        font.pixelSize: 16
        color: "white"
    } // toastLabel
    onAboutToShow: {
    function start(toastText) {
        toastLabel.text = toastText
        if(!toastTimer.running) {
        } else {
    } // function start
} // popup toastPopup

A Timer is used to close the Toast. If a new message should be displayed before first timeout reached, a ‘restart()‘ is done. It’s important to use restart() instead of start() to be sure that timeout is reset.

Using a Toast is easy done. From Settings – if something was modified – a Toast is shown:

    PopupSettings {
        id: popupSettings
        onAboutToHide: {
            if(popupSettings.update()) {
                popupToast.start(qsTr("Settings modified"))
            } else {
    } // popupSettings

    // PopupToast
    PopupToast {
        id: popupToast
        onAboutToHide: {

Here’s the Toast:


SideBar Navigation

Using a Bottom Navigation Bar in Landscape occupies worthful space and doesn’t really look good with only 3 – 5 Buttons.

For Tablets and Desktop Google recommends to use a SideBar – so I implented a SideBar which will be shown automagically in Landscape.






In Landscape the TitleBar is hidden completely or floating. How a floating TitleBar is implemented I explained in previous Example.

Bottom Navigation

How’s the Bottom Navigation done ?


This is the data model:

 property var navigationModel: 
    [{"name": "Car", "icon": "car.png", "source": "../pages/PageOne.qml"},
     {"name": "Bus", "icon": "bus.png", "source": "../pages/PageTwo.qml"},
     {"name": "Subway", "icon": "subway.png", "source": "../pages/PageThree.qml"},
     {"name": "Truck", "icon": "truck.png", "source": "../pages/PageFour.qml"},
     {"name": "Flight", "icon": "flight.png", "source": "../pages/PageFive.qml"}]
 property int navigationIndex: 0
 onNavigationIndexChanged: {

From this data model the ToolBar can be created:

// The Bar
Pane {
    id: myBar
    z: 1
	// ...
    height: 56
    background: Rectangle {
        color: primaryColor
    RowLayout {
        focus: false
        anchors.left: parent.left
        anchors.right: parent.right
        spacing: 0
        Repeater {
            model: navigationModel
            NavigationButton {
                id: myButton
                isColored: false
        } // repeater
    } // RowLayout
} // bottomNavigationBar
// The Buttons
ToolButton {
    id: myButton
    // ...
    property bool isActive: index == navigationIndex
    // ...
    height: 56
    width: myBar.width / navigationModel.length
    Column {
        spacing: 0
        topPadding: myButton.isActive || !suppressInactiveLabels? 0 : 6
        anchors.horizontalCenter: parent.horizontalCenter
        Item {
            anchors.horizontalCenter: parent.horizontalCenter
            width: 24
            height: 24
            Image {
                id: contentImage
                width: 24
                height: 24
                verticalAlignment: Image.AlignTop
                anchors.horizontalCenter: parent.horizontalCenter
                source: "qrc:/images/"+myIconFolder+"/"+modelData.icon
                opacity: isActive? myBar.activeOpacity : myBar.inactiveOpacity
            ColorOverlay {
                id: colorOverlay
                visible: myButton.isColored && myButton.isActive
                anchors.fill: contentImage
                source: contentImage
                color: primaryColor
        } // image and coloroverlay
        Label {
            visible: myButton.isActive || !suppressInactiveLabels
            anchors.horizontalCenter: parent.horizontalCenter
            text: modelData.name
            opacity: isColored? (isActive? 1.0 : 0.7) : (isActive? myBar.activeOpacity : myBar.inactiveOpacity)
            color: isColored? (isActive? primaryColor : flatButtonTextColor) : textOnPrimary
            font.pixelSize: myButton.isActive? fontSizeActiveNavigationButton : fontSizeInactiveNavigationButton
        } // label
    } // column
    onClicked: {
        navigationIndex = index
} // myButton

To show the destination from Button clicked, a StackView is used. This StackView always only shows one Control, which will be replaced if ToolButton changes index. In this Example APP we only use Pages – in a real-life-app you’ll replace StackView root object with StackView, SwipeView, TabBar etc.

Please note: There’s a InitialItemPage – this Page will show a BusyIndicator to be sure that there’s something visible at startup. Probably you won’t see this Page because the first Page will be loaded fast enough, but in real-life-apps it could take some time to instantiate a complex node.

The StackView:

    StackView {
        id: rootPane
        focus: true
        // anchors......
        initialItem: InitialItemPage{}

        replaceEnter: Transition {
            PropertyAnimation {
                property: "opacity"
                from: 0
                duration: 300
        replaceExit: Transition {
            PropertyAnimation {
                property: "opacity"
                from: 1
                duration: 300

        // support of BACK key
		// ... see sourcecode
		// some Shortcuts
		// see sourcecode

        Repeater {
            id: destinations
            model: navigationModel
            Destination {
                id: destinationLoader
            Component.onCompleted: {
                destinations.itemAt(0).active = true
        function firstDestinationLoaded() {
            fab.visible = true

        function activeDestination(navigationIndex) {
            if(destinations.itemAt(navigationIndex).status == Loader.Ready) {
            } else {
                destinations.itemAt(navigationIndex).active = true

    } // rootPane

StackView creates Destinations – a Destination is a Loader.

Loader {
    id: pageLoader
    active: false
    source: modelData.source
    onLoaded: {
        if(index == 0) {

All Destinations are inactive at the beginning. As soon as the Repeater has created all Destinations, the first one will become active: true, which will cause the source to be instantiated. From signal loaded() the Item will replace the current root item from StackView.

In this Example APP all Destinations are following same policy and created lazy the first time used and then will stay instantiated whole app lifecycle. Later in more complex Drawer Example we’ll use different policies.

StackView has no currentIndex. To manage Destinations from Button clicked we set navigationIndex – so it’s easy to know if a Button is active: index == navigationIndex, where index is automatically provided from Repeater.


You learned HowTo customize Qt Quick Controls 2 to implement a Bootom Navigation Bar or Side Navigation Bar.

Using Bottom Navigation, a TabBar, a StackView or a SwipeView are not the only ways to navigate – stay tuned for the next Example App using a sliding Drawer together with Pages, StackView, SwipeView and TabBar.

← Back (Tab Bar APP)

→ Next Article (Drawer Navigation App)

⇐ Home (Overview / Topics)



This is part 4 of a series of demo apps helping you to understand Qt 5.7 for x-platform development on Android and iOS.

You should have read the blogs about my first app using Qt 5.7 Material Style, my second app (StackView Example) and my third app (SwipeView Example) before reading on.

This time I’ll explain HowTo use a TabBar – one of the new Qt Quick Controls 2.

Coming from BlackBerry10 Cascades ? TabBar is similar to a SegmentedControl.

You should have installed Qt 5.7 RC.

New to Qt 5 development ? Please read my blog series from the beginning to learn some basic stuff and to understand this app.


TabBar Example App:

  • TabBar allows to easy navigate through content
  • There are 5 Pages the User can access
  • When a Page is loaded: call init()
  • Before a Page is destroyed: call cleanup()
  • TabBar Design can be configured from Settings tapping on Floating Action Button (FAB)

The Source

This app can be downloaded as Open Source from  https://github.com/ekke/tab_pages_x

Project structure and .pro

The project structure is similar to my StackView or SwipeView Example Apps – we’re also using 5 Pages here for TabBar to make it easy for you to compare. Pages are named same as for the StackView and SwipeView apps, but sourcecode is slightly different.

The other Apps have used Raised and Flat Buttons inside Pages – this time I’m using a customized 48 dp Image Button:

ButtonIconActive {
    imageName: tabButtonModel[1].icon
    imageSize: 48
    onClicked: {


Button {
    id: button
    // default Image Size 24x24
    property alias imageName: theIcon.imageName
    property alias imageSize: theIcon.imageSize
    focusPolicy: Qt.NoFocus
        IconActive {
        id: theIcon
        Rectangle {
        id: buttonBackground
        implicitHeight: imageSize + 24
        implicitWidth: imageSize + 24
        color: button.pressed ? accentColor : "transparent"
        opacity: button.pressed ? 0.12 : 1.0
    } // background

Popups now are in an extra Sources directory and /tabs contains TabBars and TabButtons (QML):


main.cpp and ApplicationUI (C++) are similar to the other apps (One Page Example App, StackView Example, SwipeView Example)

TabBar Design Choices

Google Material Style Guide gives you choices HowTo design a TabBar, Qt 5.7 enables you to implement your choice:


As you can see, TabBar can be part of your ToolBar or placed below, a TabButton can be done as pure-text Button, Icon-only Button or Icon plus Text. Of course you can use TabBar without a ToolBar, too.

Customizing is easy done – this is the TabButton represented by Icon-only-Design.


TabButton {
    property color theButtonColor: accentColor
    property string theIconFolder: iconFolder
    property alias hasOverlay: colorOverlay.visible
    property real theOpacity: 1.0
    focusPolicy: Qt.NoFocus
    height: 48
        Item {
        Image {
            id: contentImage
            anchors.centerIn: parent
            horizontalAlignment: Image.AlignHCenter
            verticalAlignment: Image.AlignVCenter
            source: "qrc:/images/"+theIconFolder+"/"+modelData.icon
            opacity: colorOverlay.visible? 1.0 : theOpacity
        ColorOverlay {
            id: colorOverlay
            visible: true
            anchors.fill: contentImage
            source: contentImage
            color: index == navPane.currentIndex ? theButtonColor : Qt.lighter(theButtonColor)
    } // item

Placed inside ToolBar, ColorOverly isn’t used (invisible)

Pplaced below the ToolBar, ColorOverlay tints the Image with accent color.

TabButtons fixed vs scrolling

Sometimes not all Buttons or Text fits into available width, so it makes sense to use a scrollable TabBar:

TabButton {
    // ...
    width: tabBarIsFixed? myTabBar.width / tabButtonModel.length  
	       : Math.max(112, myTabBar.width / tabButtonModel.length)


TabBar Settings (Popup)

To configure the TabBar Settings there’s another Popup:


Open the Settings Popup from Floating Action Button (FAB):


    FloatingActionButton {
        id: fab
        property string imageName: "/settings.png"
        z: 1
        anchors.margins: 16
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        imageSource: "qrc:/images/"+iconOnAccentFolder+imageName
        backgroundColor: accentColor
        onClicked: {
    } // FAB
// ...
    function showSettings() {
        popupSettings.tabBarIsFixedSettings = tabBarIsFixed
// ...
    PopupSettings {
        id: popupSettings
        onAboutToHide: {
    } // popupSettings

PopupSettings used some new Controls: RadioButtons inside a Frame:

Frame {
    ColumnLayout {
        anchors.fill: parent
        spacing: 6
        RadioButton {
            id: radioText
            focusPolicy: Qt.NoFocus
            text: qsTr("Buttons Text only")
            checked: tabButtonDesignSettings == 0
            onCheckedChanged: {
                tabButtonDesignSettings = 0
        RadioButton {
            id: radioIcon
            focusPolicy: Qt.NoFocus
            text: qsTr("Buttons Icon only")
            checked: tabButtonDesignSettings == 1
            onCheckedChanged: {
                tabButtonDesignSettings = 1
        RadioButton {
            id: radioTextAndIcon
            focusPolicy: Qt.NoFocus
            text: qsTr("Buttons Icon and Text")
            checked: tabButtonDesignSettings == 2
            onCheckedChanged: {
                tabButtonDesignSettings = 2

As already discussed in previous articles: To make Shortcuts work well, we set Qt.NoFocus for RadioButton.

This Popup follows a Default-Button-Concept, where ‘OK‘ is default (colored with Accent Color)

Even if user clicks outside the Popup to close, changed values will be updated:

Popup {
    id: popup
    // ...
    // default behavior for this Popup: OK Button Clicked
    property bool isOk: true
	// ...
    RowLayout {
        ButtonFlat {
            id: cancelButton
            text: qsTr("Cancel")
            textColor: popupTextColor
            opacity: opacityBodySecondary
             onClicked: {
                isOk = false
        } // cancelButton
        ButtonFlat {
            id: okButton
            text: qsTr("OK")
            textColor: accentColor
            onClicked: {
                isOk = true
        } // okButton
    } // row button
    // ...
    function update() {
        if(isOk) {
            tabBarIsFixed = tabBarIsFixedSettings
            tabButtonDesign = tabButtonDesignSettings
            tabBarInsideTitleBar = tabBarInsideTitleBarSettings
	// ...
// ...
// from main.qml:
// ...
onAboutToHide: {
// ...


You can define ToolTips if you want to use this to guide your users. I have implemented ToolTip on ‘Bus’ Button (First Tab).

    ToolTip.visible: pressed
    ToolTip.delay: 500
    ToolTip.text: qsTr("Take a look at the Bus schedule")


Floating Header

Using a ToolBar together with TabBar as ‘header‘ could occupy too much space in Landscape.

Coming from BlackBerry 10 Cascades ? In Cascades you can configure TitleBarScrollBehavior as NonSticky to make the TitleBar scrollable. I implemented something similar here.

Using a Loader this is easy done:

ApplicationWindow {
    property bool isLandscape: width > height
    // ...
    header: isLandscape? null : titleBar

    Loader {
        id: titleBar
        visible: !isLandscape
        active: !isLandscape
        source: titleAndTabBarSource
        onLoaded: {
            if(item) {
                item.currentIndex = navPane.currentIndex
                item.text = qsTr("HowTo move from A to B")
    Loader {
        id: titleBarFloating
        visible: isLandscape
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.right: parent.right
        active: isLandscape
        source: titleAndTabBarSource
        onLoaded: {
            if(item) {
                item.currentIndex = navPane.currentIndex
                item.text = qsTr("HowTo move from A to B")

Portrait scrolling:


Landscape scrolling:


Tandem: TabBar and SwipeView

From Google Material Style Guide: You must be able to Tap on a TabButton or to swipe from content to navigate.

From Qt 5.7 TabBar: Tabs must work together with Controls providing ‘currentIndex’.

So it’s the best way to use a SwipeView to show the content and to bind the currentIndex to TabBar.

We already discussed SwipeView in detail here. SwipeView example app uses Loader to load / unlaod current Page and next / previous Pages.

For the TabBar I did it slightly different using ‘Lazy Loading‘: at Application Start the first two Tabs are pre-loaded. All other Pages will be loaded if needed, and stay loaded while App is running.

Take a look at main.qml to see how all this stuff is implemented.

To define the TabButtons first time a Repeater is used:

Repeater {
    model: tabButtonModel
    TabButton {
        text: modelData.name
        width: ...
} // repeater

Coming from BlackBerry Cascades ? There’s nothing like a Repeater.

Repeater makes it easy to iterate through a data model and create Controls. In this case the tabButtonModel is designed in main.qml:

    property var tabButtonModel: 
	    [{"name": "Car", "icon": "car.png"},
         {"name": "Bus", "icon": "bus.png"},
         {"name": "Subway", "icon": "subway.png"},
         {"name": "Truck", "icon": "truck.png"},
         {"name": "Flight", "icon": "flight.png"}]

Each data object has a ‘name’ and an ‘icon’ property and can be accessed inside TabButton using modelData.name and modelData.icon.

TabBar Navigation

Similar to StackView and SwipeView Examples you can go different ways to navigate between Pages with tabs:

  • click on one of the TabButtons in TabBar
  • click on a Image Button to go to another Page (Tab)
  • click on Android System ‘Back’ key to go one Tab back to the left (this is no default behavior – ony an example what you can do with app-specific navigation)
  • swipe using your fingers to go to next Page (Tab) left or right
  • use Shortcuts (see StackView example about Shortcuts)


Using BlackBerry PRIV – or connected Bluetooth Keyboard Shortcuts making it easy to navigate to Tabs 1 … 5 or next / previous Tab:



You learned HowTo use a TabBar as another way to navigate through some Pages. It depends from your use-cases what will fit best your requirements.

Using a TabBar, a StackView or a SwipeView are great to navigate through many APPs. What if there are some areas you need to switch between ? Then a sliding Drawer will be the solution to manage even really complex APPs. Before taking a look at Qt Quick Controls 2 ‘Drawer’ – there’s another way if your app can be managed by 3 to 5 buttons: Google introduces Bottom Navigation as part of Material Style. The next example APP will customize Qt Quick Controls to use Bottom Navigation.

← Back (Swiped Pages APP)

→ Next Article (Bottom Navigation APP)

⇐ Home (Overview / Topics)

Install Qt 5.7

June 5, 2016 — Leave a comment

UPDATE: 2016-06-16: Qt 5.7 Release is out ! You can still follow my descriptions below from 5.7 RC – process is similar.

This blog series is about the new Qt Quick Controls 2 to develop mobile apps for Android and iOS.

Before going on you should have read my blog – esp. on ‘Prepare for Android / iOS‘ and ‘Prepare Devices

Besides Qt 5.7 you’ll also get a new Qt Creator 4.0.2.

Perhaps you already have an older version of Qt already installed, you can use the Maintenance Tool to update. I’m always doing a fresh install for each Beta, RC or Release.

Before downloading and installing you should know if you want to install the Open Source or Commercial version of Qt for Application Development.

Please take a look at Qt FAQ‘s and also my blog post about licensing and the new license for small Startups and Independent Developers.

I’m using the Commercial version for Startups – see Qt’s offer here: https://www.qt.io/start-up-plan/

Read more about Open Source vs Commercial also in my blog about ‘Install Qt 5.6

Here are my steps to download and install Qt 5.7 RC (commercial):

Install Qt 5.7

Go to your Qt Account – Downloads and select the Qt Online Installer:



UPDATE: now: 2.0.3-2 for Qt 5.7 release:


UPDATE: now: qt-unified-mac-x64-2.0.3-2-online.dmg



Here’s my download on OSX:



Double click to install:



Log into your Account:


Select the folder where to install:



As next select your components:



and wait for the installer:



If Installer finished, I’m not launching Qt Creator yet.



Start Qt Creator with -settingsPath

All Qt Creator instances by default share the settings. Having the new Qt Creator 4.0.2 and old 3.6.2 using the same settings is no good idea. Also I want to use different working directories for my Qt 5.6, 5.7 Beta, 5.7 RC and the new Qt 5.7 Release.

You can start Qt Creator wit parameter -settingsPath – here’s HowTo do this from OSX:

Search for the Qt Creator.app from Qt 5.7 and do a right-click on the app. Here’s the content:


rename Qt Creator to something like Qt Creator-bin:


From a Text Editor create a Script to execute the Qt Creator-bin with a parameter:



Save this file named “Qt Creator” besides the Qt Creator-bin:_


Now you can start Qt Creator, which will execute the script:


Qt Creator will create the QtProject folder where all the configuration settings are stored.

Now you can start multiple Qt Creator versions without any collision.

Qt Creator 4.0.2

First thing you’ll notice after starting Qt Creator 4.0.2 is the new default flat design. If you don’t like it you can go back to the old one or a dark theme:



I’m also changing the language from german to english.

And here’s the new flat design:


Qt Creator Preferences Working Directory

Set your working directory for 5.7, if you are using different directories as I’m doing:



Qt Creator Preferences Android

Take a look at your Android preferences:


Select your SDK and NDK locations and check ‘Gradle’:


Qt Creator External Tools

I’m developing business apps and business apps always need support of languages (i18n). Configuring the External Tools for Linguist (Qt’s Tool to translate text from your QML and C++ sources) will make it more comfortable.

As first step we’ll add the Linguist App.You’ll find the Linguist at 5.7 –> clang_64 –> bin:


I like to use Tools in english, but the language cannot be changed yet for Linguist, so the trick is to rename the translations file, which in my case is 5.7 –> clang_64 –> translations –> linguist_de.qm:


Under Preferences –> Environment –> External Tools there already exist access to commands for lupdate and lrelease. (lupdate is looking for the strings you marked as translatable and to create or update the translation files <app>.ts. Using Linguist or external tools you can then translate the strings. lrelease compiles these translations from *.ts into *.qm. Only *.qml files will be deployed to your device)

I found out that the default configuration doesn’t work on Android and iOS – please change the executable:



Test if Linguist will start. From External Tools


Linguist should start:


Verify Installation: Gallery Qt Quick Controls 2

As last step verify if all is correct configured.

Best way to do this and to get a first impression of new QtQuick Controls 2 is to run the new Quick Controls 2 Gallery App.

From Overview – Examples search for “Gallery” and select the right one:


Configure your project for Android / iOS:


Now run on your device(s).


Select your Device – here’s my BlackBerry PRIV (Android 6.0.1):


… and the Gallery App is running:


Now you can try out all the new Controls.

Congrats – now you have installed Qt 5.7.  Some more appetizers ?

Clone my Examples from Github and Run

  1. First app with One Page
  2. StackView
  3. SwipeView
  4. TabBar
  5. Bottom Navigation
  6. Drawer Navigation

Please follow my blog series: https://appbus.wordpress.com/category/qt-for-mobile/overview/

← Back (Qt Community (Wiki, Forum, Lists))

→ Next Article (Qt Creator Intro)

⇐ Home (Overview / Topics)