Overview

This is our first sample app to demonstrate HowTo use Material design and Qt 5.7 for mobile x-platform development. This app is not a real-life-app – there’s nothing about performance, dynamic-loading, data-binding, caching or so. Stay tuned – there will be more sample apps next weeks to demonstrate all what you need to develop x-platform business apps for (BlackBerry 10), Android, iOS, (later also Windows10).

The goal of this app is to demonstrate:

  • new Qt Quick Controls 2 (qt.labs.controls)
  • customizing Controls
  • customer-specific layouting
  • dark and light theme
  • Material colors and fonts
  • Icons for different DPI
  • internationalization
  • tips to structure your project

You should have installed Qt 5.7 Beta.

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

Attention: Qt 5.7 Beta still uses qt.labs.controls instead of Qt Quick Controls 2 – this will change with Qt 5.7 RC.

This app is a simple one-page app without navigation and is tested on Android (BlackBerry PRIV, Android 6.0.1) and iOS (iPhone 6s, iOS 9.3)

Hint: there are many ways to manage colors, fonts, opacity, images – perhaps this app will help you to find your way.

one_x_a_01

The Sources

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

Project structure and .pro

Coming from another IDE (like Eclipse Momentics) you’ll soon recognize that Qt Creator projects are not synced with the underlying file system. So there are some more manual steps to have an easy access to your files.

proj_structure

Adding C++ sourcefiles or headers to your project will automatically create an entry under SOURCES or HEADERS in your .pro (right part) and also show this in your project structure (left part). Same for Resource files (*.qrc) – they’re automatically part of your .pro and project structure.

If you already have downloaded the sources from github you can try to open the content tree of the qrc file. It’s not really comfortable for a project with many files and folders.

In this blog entry I described HowTo manage translations. LUPDATE and LRELEASE are looking for translatable strings from C++ and QML. C++ sources are already found in .pro under SOURCES. To make QML files available as SOURCES for translation, the lupdate_only section adds QML files to SOURCES for translation without confusing the compiler. A nice side effect of this is getting the QML files also placed under SOURCES in your project structure. See how using wildcards makes it easy to manage in .pro.

There are some more files you want to have easy access: images, translations, textfiles. Placing these files under OTHER_FILES inside .pro makes them visible at the left side.

Now our project structure inside Qt Creator looks similar to the underlying file system.

Hint: adding new files to resources sometimes doesn’t make them visible at the left side immediately. To trigger the update open the .pro, add a space and save – then it appears – sometimes needs a second or so. (TODO: bugreport)

main.cpp

main.cpp enables High DPI Scaling, Material style and translation:

int main(int argc, char *argv[])
{
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    qputenv("QT_LABS_CONTROLS_STYLE", "material");
    QGuiApplication app(argc, argv);
    QTranslator translator;
    if (translator.load(QLocale(), QLatin1String("one_page_x"), QLatin1String("_"), QLatin1String(":/translations"))) {
        app.installTranslator(&translator);
    } else {
        qDebug() << "cannot load translator " << QLocale::system().name() << " check content of translations.qrc"; 
    } 
    ApplicationUI appui; 
    QQmlApplicationEngine engine; 
    QQmlContext* context = engine.rootContext(); 
    context->setContextProperty("myApp", &appui);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

main.cpp also gives access to ApplicationUI from QML via context ‘myApp‘.

Application UI (C++)

Coming from BlackBerry 10 Cascades ? There’s also an ApplicationUI managing all app-specific stuff – so I have named it same here😉 Let’s take a look at the header, where you’ll find some Q_INVOKABLE methods:

     Q_INVOKABLE
     QStringList swapThemePalette();

     Q_INVOKABLE
     QStringList defaultThemePalette();

     Q_INVOKABLE
     QStringList primaryPalette(const int paletteIndex);

     Q_INVOKABLE
     QStringList accentPalette(const int paletteIndex);

     Q_INVOKABLE
     QStringList defaultPrimaryPalette();

     Q_INVOKABLE
     QStringList defaultAccentPalette();

Q_INVOKABLE marks a method to be invokable from the UI (QML).

Invoke Application UI from QML

A QStringList from C++ is automatically mapped to a JavaScript Array in QML:

ApplicationWindow {
    ....
    property variant primaryPalette: myApp.defaultPrimaryPalette()
    property color primaryLightColor: primaryPalette[0]
    property color primaryColor: primaryPalette[1]
    property color primaryDarkColor: primaryPalette[2]
	....

This app is a playground for Material Colors, Font sizes and more. To make this easy I created some constants you can access via the Q_INVOKABLE methods.

UI Constants (C++)

Google Material Design Guide provides  a default Color Palette.

Qt also recommends to use one of the predefined default colors as the primary color and another one as the accent color.

For each predefined color there are also some predefined shades of these colors. Following the Google Material Design Guide there are some use-cases where it makes sense besides the primary color also to use a something-lighter and a something-darker primary color.

Inspired by this page: MaterialPalette.com I’m using shade 500 as primary color, shade 100 as primary light color and shade 700 as primary dark color, per example for Material.Red:

google_color_red

Qt 5.7 per ex. uses the primary color as background for a ToolBar and (starting with Qt 5.7 RC) also “knows” the correct color for Text (Material.foreground) – in this case: White.

From the screenshot above you can see that using a lighter or darker primary color the foreground color can be different.

But there’s not only Text on primary colors – you can place Icons there.

Google recommends to use white or black images (depending from the used color)  together with a specific opacity for images and text.

To make it easier to manage I created a palette for each predefined Material color:

  • primaryLightColor (shade 100)
  • primaryColor (shade 500)
  • primaryDarkColor (shade 700)
  • textOnPrimaryLight (white or black text color)
  • textOnPrimary (white or black text color)
  • textOnPrimaryDark (white or black text color)
  • iconOnPrimaryLightFolder (images/dark or images/white)
  • iconOnPrimaryFolder (images/dark or images/white)
  • iconOnPrimaryDarkFolder (images/dark or images/white)

For Material.Red here are the values:

    static const QStringList materialRed {
	    "#FFCDD2", "#F44336", "#D32F2F", 
		"#000000", "#FFFFFF", "#FFFFFF", 
		"black", "white", "white"};

Now it’s easy to understand the code above (Invoke Application UI from QML): myApp.defaultPrimaryPalette() gives you an Array and per ex. primaryPalette[2] provides the primary dark color (#D32F2F). You can use these palettes for primary and accent colors.

Qt 5.7 also supports Material Themes dark and light and automagically knows the text color to be used: white on dark theme and black on light theme. But the real-life story is more difficult and there are some situations where you have to set a color or opacity depending from dark or light theme.

So I also created a dark and light palette containing this information:

static const QStringList darkPalette{"#FFFFFF", "#424242", 
    "1.0", "0.70", "0.12",
	"1.0", "0.3", "white", "1"};
static const QStringList lightPalette{"#000000", "#FFFFFF", 
    "0.87", "0.54", "0.12",
	"0.54", "0.26", "black", "0"};

Now it’s easy always to use the correct color, opacity and to know if the icons should be from dark or white images folder.

That’s all from C++ – let’s take a look at the UI side of the app.

ApplicationWindow (main.qml)

The root object of our Qt Quick 2 app is the ApplicationWindow{}. Developing mobile apps you don’t need to set width and height, because the ApplicationWindow always grabs the total available space. We also don’t need to set the title, because we’re using a header containing the ToolBar.

It’s important to set visible: true – otherwise you’ll only get an empty screen.

The structure of our app looks like this:

// imports
ApplicationWindow {
    visible: true
    // properties
    header: {}
    // optional footer {}
    Flickable {}
    // functions
    Popup {}
}

imports:

import QtQuick 2.6
import QtQuick.Layouts 1.3
import Qt.labs.controls 1.0
import Qt.labs.controls.material 1.0
import QtGraphicalEffects 1.0
import "common"
import "demo"

Taking a look at the imports you’ll notice two project-specific imports: “common” and “demo” – both are folders containing QML files:

  • common: QML files used from some apps – you’ll find them also in our next apps
  • demo: QML files used to demonstrate some use-cases

It’s always a good idea to structure your QML files – this will make it easier to find and to manage them.

properties:

    // primary and accent properties:
    property variant primaryPalette: myApp.defaultPrimaryPalette()
    property color primaryLightColor: primaryPalette[0]
    property color primaryColor: primaryPalette[1]
    property color primaryDarkColor: primaryPalette[2]
    property color textOnPrimaryLight: primaryPalette[3]
	...
    Material.primary: primaryColor
    Material.accent: accentColor
	...
    // theme Dark vs Light properties:
    property variant themePalette: myApp.defaultThemePalette()
    property color dividerColor: themePalette[0]
    property color cardAndDialogBackground: themePalette[1]
    property real primaryTextOpacity: themePalette[2]
	...
    property int isDarkTheme: themePalette[8]
    onIsDarkThemeChanged: {
        if(isDarkTheme == 1) {
            Material.theme = Material.Dark
        } else {
            Material.theme = Material.Light
        }
    }
	...

ApplicationWindow is the root UI Object and will always be “known” from UI Controls down the tree of controls. It makes sense to place properties you need from your UI controls here as part of the ApplicationWindow. You’ll find there properties from primary palette, accent palette, theme palette and more.

If not using the default values, you should also set some Qt 5.7 Material properties:

  • Material.primary
  • Material.accent
  • Material.theme

Hint: There are also other ways to set these values – please take a look at Qt docs: https://doc-snapshots.qt.io/qt5-5.7/qtquickcontrols2-material.html

functions:

    function switchPrimaryPalette(paletteIndex) {
        primaryPalette = myApp.primaryPalette(paletteIndex)
    }
    function switchAccentPalette(paletteIndex) {
        accentPalette = myApp.accentPalette(paletteIndex)
    }

Functions from root (ApplicationWindow) can also be reached from other QML objects created on top. There are only two functions in this app to switch the primary or accent palette.

ApplicationWindow –> header / ToolBar

header‘ can be used for an application-wide TitleBar. For this application I decided only to have a simple header with a title text and an option menu – all placed on primary color. To make it easy to reuse this in other apps I created a SimpleTextTitle.qml in /commons. This makes the header easy to define inside the ApplicationWindow:

    header: SimpleTextTitle {
        text: qsTr("A simple 1 - Page APP")
    }

/commons/SimpleTextTitle.qml:

ToolBar {
    id: titleToolBar
    property alias text: titleLabel.text

    RowLayout {
        focus: false
        spacing: 6
        anchors.fill: parent
        LabelTitle {
            id: titleLabel
            text: "ekke"
            leftPadding: 16
            elide: Label.ElideRight
            horizontalAlignment: Qt.AlignHCenter
            verticalAlignment: Qt.AlignVCenter
            color: textOnPrimary
        }
        ToolButton {
            Image {
                id: buttonImage
                anchors.centerIn: parent
                source: "qrc:/images/"+iconOnPrimaryFolder+"/more_vert.png"
            }
            onClicked: {
                optionsMenu.open()
            }
            Menu {
                id: optionsMenu
                x: parent.width - width
                transformOrigin: Menu.TopRight
                MenuItem {
                    text: isDarkTheme? qsTr("Light Theme") : qsTr("Dark Theme")
                    onTriggered: {
                        themePalette = myApp.swapThemePalette()
                    }
                }
                MenuItem {
                    text: headlineColoredPrimary? qsTr("Headline Accent Color") : qsTr("Headline Primary Color")
                    onTriggered: {
                        headlineColoredPrimary = !headlineColoredPrimary
                    }
                }
            } // end optionsMenu
        } // end ToolButton
    } // end RowLayout
} // end ToolBar

The header in fact is a ToolBar – one of the new Qt Quick Controls 2. A ToolBar can be placed as header or footer, where ToolBar.Header position is default position for Material styled apps. Background of a ToolBar is Material.primary color. To place some controls inside a ToolBar, best way is to use a RowLayout. Our RowLayout contains a Label and a ToolButton filling the parent (ToolBar) completely.

toolbar

ToolButton is a Button to be placed inside a ToolBar. In this case the ToolButton is presented as an Image. Please notice how the ‘source‘ is constructed using the iconOnPrimaryFolder – a property from our root object (ApplicationWindow). From our primary palette we know if the image is placed inside the ‘/black‘ or ‘/white’ folder for the selected primary color. Clicking on the Button opens a Menu:

toolbutton_menu

From this Menu you can switch the Theme between dark and light and you can switch the color for all Headlines between Accent and Primary color. Switching the Theme is done invoking a methode from ‘myApp’ (ApplicationUI.cpp): myApp.swapThemePalette() – the return value (QStringList) is set as a property in ApplicationWindow: themePalette.

The Label itself is a customized Label:

/commons/LabelTitle.qml:

Label {
    Layout.fillWidth: true
    font.pixelSize: fontSizeTitle
    opacity: opacityTitle
}

It’s important to set Layout.fillWidth: true. This will cause the Label to use as much space as possible, so the ToolButton will be placed at the right side. You can test this changing the orientation from Portrait to Landscape and back.

Coming from BlackBerry10 Cascades and looking for a TitleBar ? Qt 5.7 ApplicatrionWindow -> header -> ToolBar is what you need.

Hint: I’m using all the properties from ApplicationWindow without a prefix. This works because in my app the names are unique. If you cannot guarantee this, prefix the porperties, per ex. appWindow.textOnPrimary.

ApplicationWindow –> Popup

Popup is also new from Qt Quick Controls 2. This Popup contains a list of all Material colors and allows you to select another color. Another blog article will take a look at Lists in detail. For now you can take a look at /common/PopupPalette.qml. Inside the ApplicationWindow the Popup is defined this way:

    PopupPalette {
        id: popup
    }

Hint: Coming from BlackBerry 10 Cascades ? To add Controls like Dialogs, Popups, Toasts, … you have to place them inside attachedObjects[] – in Qt 5.7 you don’t have to do this. Qt “knows” that this is a control which must be opened to appear.

ApplicationWindow –> Flickable (the content)

It’s a good idea to use a Flickable as outer Control if you want to flick the content with your fingers. Try it out with or without a Flickable to “feel” the difference. Having an extra Flickable was a new concept for me.

What’s inside our Flickable in this app ?

Flickable {
        id: flickable
        contentHeight: root.implicitHeight
        anchors.fill: parent
        Pane {
            id: root
            anchors.fill: parent
            ColumnLayout {
                anchors.right: parent.right
                anchors.left: parent.left
                // ... more or less complex controls ...
            } // col layout
        } // root
        ScrollIndicator.vertical: ScrollIndicator { }
    } // flickable

For a newcomer it was not easy to figure it out HowTo set correctheight. From the abstract above you’ll see how it works:

  • The Flickable must know the contentHeight
  • ContentHeight will be calculated by the inner Pane’s implicitHeight
  • The Flickable has to fill the parent (ApplicationWindow)
  • The inner Pane also has to fill the parent (Flickable)

Don’t forget to set a vertical ScrollIndicator to make the Flickable scrollable.

The inner control containing all the content is a Pane: a new control from Qt Quick Controls 2. A Pane knows the current Theme and Style and will get the correct background automagically from Qt Material styling. It’s a good idea to use Pane instead of Rectangle if you need a container using correct background.

Hint: Pane has a default padding. If for some reason you have to use a Pane inside a Pane and want to align the controls of both you must set padding to 0 for nested Panes.

Placing controls row by row inside your Pane you should use a ColumnLayout anchored at left and right on parent (Pane). Using a ColumnLayout the content will be rearranged if orientation of your device is changed from Portrait vs Landscape.

If a Row contains some controls side by side, you should use a RowLayout for this.

Hint: Coming from BlackBerry10 Cascades ? ColumnLayout is like StackLayout with orientation TopToBottom and RowLayout is like StackLayout with orientation LeftToRight.

Customer – specific Layouting

I’m developing business apps for SMB’s and Enterprises where many usecases will be to display some data. Data entry will be part of another sample app. Fields should be aligned and automatically rearranged if orientation changes. Let’s imagine we must solve these user-requirements:

Some rows of data containing a Label at the left side, another Label or Switch or Checkbox and at the right side a transparent or colored bar. First Label should occupy 1/3, second control 2/3 of available width automatically adjusted if changing orientation.

biz_row_layout

Here’s how it looks in Portrait:

portrait_fields

and in Landscape:

landscape_fields

All customized controls can be found at /demo/*.qml – here’s the customized control to display two Labels and the colored bar:

/demo/LabelLabelBarRow.qml:

RowLayout {
    id: labelLabelRow
    property alias text1: label1.text
    property alias text2: label2.text
    property alias barColor: rightBar.color
    // implicite fillWidth = true
    spacing: 20
    LabelBodySecondary {
        id: label1
        leftPadding: 10
        Layout.preferredWidth : 1
        wrapMode: Text.WordWrap
        text: ""
    }
    LabelBody {
        id: label2
        leftPadding: 2
        Layout.preferredWidth: 2
        wrapMode: Text.WordWrap
        text: ""
    }
    Rectangle {
        id: rightBar
        anchors.right: parent.right
        anchors.rightMargin: 6
        Layout.fillWidth: true
        Layout.minimumWidth: 10
        Layout.maximumWidth: 10
        implicitHeight: 40
        color: "Transparent"
    }
} // row layout

There are three properties (the API) to set the text of first and second label and also to set the color of the bar. First Label itself is a customized Label from /common styled as ‘secondary text’, second Label uses ‘primary text’. HowTo manage the width relation 1 : 2 ?

Coming from BlackBerry10 Cascades ? There’s a spaceQuota property at StackLayout to divide available space and I figured out that I can do something similar in Qt 5.7:)

Please follow these 3 steps:

  1. Use a RowLayout
  2. Set Layout.preferredWidth to ‘1’ for the first Label and ‘2’ for the second Label
  3. The colored or transparent bar gets a fixed size of 10

Now all is done by RowLayout:)

fillWidth is true by default, so the Layout will use all available width. Rectangle (colored bar) will be placed at the right side (anchors.right: parent.right) Now the two Labels must fill the remaining space. RowLayout uses the preferredWidth to calculate. Because preferredWidth is small it will be extended and we’ll get the 1: 2 relation.

LabelLabelBarRow can be used this way:

LabelLabelBarRow {
    text1: qsTr("Name ")
    text2: qsTr("Jane Doe")
    barColor: Material.accentColor
}

Please take a look at the other controls from /demo

Internationalization / Quantities

Qt makes is easy to translate your strings. If you haven’t done – please read my article about this topic.

You should always define your strings as translatable as seen here in my code using qsTr(“”)

Here’s how you can translate text with quantities:

LabelSwitchBarRow {
    id: multiSwitch
    property int count: checked ? 2 : 1
    text: qsTr("Translate Multi")
    switchText: qsTr("%1 piece(s)","",count).arg(count)
}

I’m using the Switch to change a property (‘count’) and I’m using this property for translations to get this in german:

quantity_switch

The translation done in Qt Linguist:

linguist_quantities

Show / Hide Fields

Displaying business informations in many cases you have to hide / show some of the content.

show-hide

Here’s one simple way to do this:

LabelSwitchBarRow {
    id: addressSwitch
    text: qsTr("Address")
}
Pane {
    id: addressBlock
    // implicite padding: 6
    leftPadding: 0
    rightPadding: 0
    anchors.left: parent.left
    anchors.right: parent.right
    visible: addressSwitch.checked
    ColumnLayout {
        anchors.right: parent.right
        anchors.left: parent.left
        LabelLabelBarRow {
            text1: qsTr("City")
            text2: qsTr("Munich")
            barColor: "Red"
        }
        LabelLabelBarRow {
            text1: qsTr("Street")
            text2: qsTr("Odeonsplatz")
            barColor: "green"
        }
        LabelLabelBarRow {
            text1: qsTr("Zip")
            text2: qsTr("80000")
            barColor: "transparent"
        }
    } // addressBlock col layout
} // addressBlock

I’m using a nested Pane as a Container for the fields I want to show under specific conditions – in this case if the addressSwitch is ON.

Simply bind the visibility of the Pane to checked stae of the Switch: visible: addressSwitch.checked – that’s all.

Don’t forget to set the Padding to 0 for the nested Pane. Don’t use a Rectangle: you will loose the theme- and style-specific background !

Switching the Theme

Switching the Theme can be done by ToolButton – Menu as described above.

To verify what happened, I’m displaying some of the theme-dependent colors and opacity values:

Light theme vs Dark Theme:

theme_switch

Selecting Primary and Accent Colors

Current selected primary colors (primary light, primary, primary dark) and accent color are displayed here:

primary_accent_colors

Tap on primary to get a list of Material predefined colors:

select primary

Color names are translated.

Tap on accent to get same list of colors, but also the primary color will be displayed to make it easier to select:

select accent

To display the list a Popup is used. (see above: Popup)

To open the Popup we need a MouseArea to detect the “Tap” on a Rectangle:

    Rectangle {
        Layout.fillWidth: true
        width: parent.width
        height: 40
        color: appWindow.primaryColor
        Label {
            leftPadding: 6
            anchors.verticalCenter: parent.verticalCenter
            wrapMode: Text.WordWrap
            text: qsTr("Primary Color: %1 --- Tap to edit","").arg(primaryColor)
            color: appWindow.textOnPrimary
        }
        MouseArea {
            anchors.fill: parent
            onClicked: {
                popup.selectAccentColor = false
                popup.open()
            }
        } // mouse
    }

Fonts, Sizes, Opacity

Google Material Design Guide – Typography – gives you all you need to know about font sizes, color and opacity.

To make it easy to use for your own app I added some properties at ApplicationWindow:

    // font sizes - defaults from Google Material Design Guide
    property int fontSizeDisplay4: 112
    property int fontSizeDisplay3: 56
    property int fontSizeDisplay2: 45
    property int fontSizeDisplay1: 34
    property int fontSizeHeadline: 24
    property int fontSizeTitle: 20
    property int fontSizeSubheading: 16
    property int fontSizeBodyAndButton: 14 // is Default
    property int fontSizeCaption: 12
    // fonts are grouped into primary and secondary with different Opacity
    // to make it easier to get the right property,
    // here's the opacity per size:
    property real opacityDisplay4: secondaryTextOpacity
    property real opacityDisplay3: secondaryTextOpacity
    property real opacityDisplay2: secondaryTextOpacity
    property real opacityDisplay1: secondaryTextOpacity
    property real opacityHeadline: primaryTextOpacity
    property real opacityTitle: primaryTextOpacity
    property real opacitySubheading: primaryTextOpacity
    // body can be both: primary or secondary text
    property real opacityBodyAndButton: primaryTextOpacity
    property real opacityBodySecondary: secondaryTextOpacity
    property real opacityCaption: secondaryTextOpacity

There are also customized Labels at /common, per ex.

/common/LabelCaption.qml:

Label {
    Layout.fillWidth: true
    font.pixelSize: fontSizeCaption
    opacity: opacityCaption
    font.capitalization: Font.AllUppercase
}

Running the app you can see them all to get an impression which to use for a specific use-case:

fonts

Icons – High DPI Support

Please read my article about High DPI support if not already done. My two test devices:

  • Android (PRIV), 540 dpi –> scaling factor: 3.5
  • iOS (iPhone 6S), 326 dpi –> scaling factor: 2.0

Images to support High DPI are named similar to iOS:

image_naming

To verify that Qt detects the correct size, I added some special images:

test@1_4x

HowTo get the Image:

Image {
    opacity: iconActiveOpacity
    source: "qrc:/images/"+iconFolder+"/test.png"
}

Here’s the result for BlackBerry PRIV: scaling factor 3.5 tries to find the @4x.png and for the iPhone 6s: scaling factor 2 tries to find the @2x.png:

icons

Using the app you can test this for your device.

Icons in Material styled apps can have different state: active or inactive and you can use the icons uncolored or colored with primary or accent.

Default Icon size is 24, but 18×18, 36×36 and 48×48 are also common sizes used. To get a feeling about the sizes I added them to this sample app.

Light theme:

icons_light

Dark theme:

icons_dark

I structured the Icon folders into black / white and sizes to make it easy to construct sources:

icon_folders

Take a look at the source to see how Icons are displayed.

Custom Control FAB (Floating Action Button)

Qt Quick Controls 2 and Material style were introduced as TechPreview in Qt 5.6 and now part of Qt 5.7

Not all UI Controls are provided yet, but it’s easy to customize existing ones. I missed the Floating Action Button – thx @jpnurmi helping me to customze:

common/FloatingActionButton.qml:

Button {
    id: button
    // image should be 24x24
    property alias imageSource: contentImage.source
    // default: primaryColor
    property alias backgroundColor: buttonBackground.color
    property bool showShadow: true
    contentItem:
        Item {
        implicitHeight: 24
        implicitWidth: 24
        Image {
            id: contentImage
            anchors.centerIn: parent
        }
    }
    background:
        Rectangle {
        id: buttonBackground
        implicitWidth: 56
        implicitHeight: 56
        color: primaryColor
        radius: width / 2
        opacity: button.pressed ? 0.75 : 1.0
        layer.enabled: button.showShadow
        layer.effect: DropShadow {
            verticalOffset: 3
            horizontalOffset: 1
            color: dropShadow
            samples: button.pressed ? 20 : 10
            spread: 0.5
        }
    }
}

There’s also a Mini FAB. There’s a property to show the shadow, wich is per default ON for a normal FAB and OFF for a Mini FAB. Setting different colors the FAB looks like this:

fab

Creating the FAB is easy done:

        FloatingActionButton {
            imageSource: "qrc:/images/"+iconOnPrimaryLightFolder+"/person.png"
            backgroundColor: primaryLightColor
        }
        FloatingActionButton {
            imageSource: "qrc:/images/"+iconOnPrimaryFolder+"/person.png"
        }

Notice the use of matching folder names to get a black or white image depending on the color.

Coming from BlackBerry10 Cascades ? A Floating Action Button should be used instead of an SignatureAction in Cascades.

Summary

While exploring this app we learned HowTo use Material colors, fonts and themes, we used some of the new Qt Qucik Controls 2 and did some first customization, did some C++ <-> QML communication (Q_INVOKABLE) and strcutured our assets (images, translations).

Hopefully I could motivate you to try out Qt 5.7 and new Qt Quick Controls 2 for mobile x-platform development.

I’ll go on and next app will demonstrate some first Navigation with Qt Quick Controls 2 StackView.

Step by step next weeks I’ll go through all use-cases needed to be solved for business app development.

All is new to me, too so I’m curious to see how well it will work😉


← Back (Resolution Independence)

→ Next Article (TBD)

⇐ Home (Overview / Topics)

Think international from the beginning

Even if you think, that you don’t need to support more then one language – it’s better to have this in mind from the beginning, because it’s hard to add later.

I’m developing business apps and business is international, so I’m always developing for multi-language support.

This article is a short summary what’s needed and covers configuration, translation and build process.

Configure Qt Creator External Tools

There’s an extra application Qt Linguist to translate and two important commands lupdate and lrelease. Using External Tools it’s easy to have access without leaving Qt Creator or the need of the command line. Here’s HowTo:

1. Configure easy access to Qt Linguist

Together with you Qt installation you got the Qt Linguist. Please take a look at the manual: http://doc.qt.io/qt-5/qtlinguist-index.html

qt_ling_manual

I’m living in Germany and always develop my APPs in english and immediately doing the translation to german. This way I always detect soon if I forgot to make a String translatable. (we’ll talk about this later) Also german words normaly need some more space so I can control how the app looks in german vs english. I already used the Qt Linguist for my BlackBerry 10 Cascades development and really like the tool.

You’ll find the Qt Linguist app here:

configure_creator_03

Thanks to tips I got from Qt community (creator list) I found out that you can open Qt Linguist directly from Qt Creator.

Preferences -> Environment –> External Tools is the key:

configure_creator_02

Fill out the description (Linguist) and path to the Executable (Tap Choose and Select Linguist)

It’s a good idea to set the Working Directory. Instead of a hardcoded path you can also use a variable: %{CurrentProject:Path} Now the Linguist always opens inside your current project.

Adding the External Tool will place it under ‘Uncategorized’ – move it via Drag-n-Drop under existing Linguist category.

Now it’s easy to start the Linguist from inside your Qt Creator:

qt-linguist-logo

configure_creator_05

From Linguist open the files to translate (.ts).

A first screenshot from Linguist so you’ll get the idea:

configure_creator_06

As I opened Qt Linguist first time, I got it in german. Unfortunately there’s no language settings as described for Qt Creator above.

This little trick does it:

configure_creator_07

Search the translation files for linguist and rename the linguist_de.qm file – now Linguist opens in english.

(I created a Feature Request: https://bugreports.qt.io/browse/QTBUG-52456)

2. Configure lupdate in External Tools

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:

06_qtc_ext_tools_04

3. Configure lrelease in External Tools

Do the same for lrelease:

06_qtc_ext_tools_05

That’s all to configure.

Make your Strings translatable

You can read in detail about this in Qt documentation:

Here’s a short starter:

To enable your app to use a Translator you have to add some lines of code into your main.cpp:

#include <QTranslator>
    // ...
    QGuiApplication app(argc, argv);

    QTranslator translator;
    if (translator.load(QLocale(), QLatin1String("my_app"), QLatin1String("_"), QLatin1String(":/translations"))) {
        app.installTranslator(&translator);
    } else {
        qDebug() << "cannot load translator " << QLocale::system().name() << " check content of translations.qrc";
    }

    QQmlApplicationEngine engine;
	// ...

Translation in your C++ sources is done using tr(), in QML files using qsTr()

QML: (simple text to be translated)

Label {
    text: qsTr("City")
}

QML: (text with arguments)

Label {
	property int theValue: 42
	text: qsTr("The answer of all is %1").arg(theValue)
}

QML: (text with arguments and quantity)

Label {
	property int count: 1
	text: qsTr("%1 piece(s)","",count).arg(count)
}

That’s all you need to know for your sourcecode.

HowTo extract translatable Strings

Now as your C++ and QML code contains all the stuff to make your Strings translatable – HowTo get these Strings out of your code to be able to translate using Qt Linguist or other solutions ?

lupdate does this. If you followed my tips above, you can use lupdate from External Tools inside Qt Creator. At first lupdate must know the languages used and also where to find the C++ and QML sources. Here are the relevant parts from my_app.pro:

TARGET = my_app
# cpp sources
SOURCES += main.cpp
# qml sources
lupdate_only {
    SOURCES +=  main.qml \
    common/*.qml \
    demo/*.qml
}
# Supported languages
LANGUAGES = de en fr
# used to create .ts files
 defineReplace(prependAll) {
     for(a,$$1):result += $$2$${a}$$3
     return($$result)
 }
 # Available translations
 tsroot = $$join(TARGET,,,.ts)
 tstarget = $$join(TARGET,,,_)
 TRANSLATIONS = $$PWD/translations/$$tsroot
 TRANSLATIONS += $$prependAll(LANGUAGES, $$PWD/translations/$$tstarget, .ts)

The compiler needs all C++ sources, lupdate also needs the qml sources. Using lupdate_only {} does the trick not to confuse the compiler. To avoid the need to create .ts files for each language the $$prependAll – stuff does this:

  • create my_app.ts
  • create my_app_de.ts
  • create my_app_en.ts
  • create my_app_fr.ts

All files are created inside project working dir at /translations – so this directory should be there.

Translate your Strings

Now open Qt Linguist from External Tools and select the .ts files.

Attention: Never open the rootfile my_app.ts – this file will always be regenerated from lupdate !.

Build and Run your APP on Android or iOS Devices

The compiled APP won’t use the *.ts files – the APPs always need the compressed compiled version *.qm.

lrelease compiles your .ts files into .qm files. Here’s the part for this in your my_app.pro:

# run LRELEASE to generate the qm files
qtPrepareTool(LRELEASE, lrelease)
 for(tsfile, TRANSLATIONS) {
     command = $$LRELEASE $$tsfile
     system($$command)|error("Failed to run: $$command")
 }

This will create the *.qm files where your *.ts files are: at root of your project dir in /translations folder.

If you take a look at the code in your main.cpp (see above) where QTranslater was loaded using :/translations as path to my_app_xx.qm files, you know from :/ that *.qm files must be part of Qt Resources.

For this from my_app.pro we’re providing a .qrc file containing all the qm files:

RESOURCES += qml.qrc \
    translations.qrc

Unfortunately the .qm files won’t automatically become part of translations.qrc. You have to add them manually. This only must be done if adding new languages. In this case you have to at the language to LANGUAGES in .pro, then run lupdate and build your project to create the new .ts and .qm files. Then you can right-click on translations.qrc and use Add Existing Files to add the .qm for the new language.

That’s it:)

Summary

I spent much time to figure this out and to find a way without use of command line. Hopefully I described it in a way to make it easy for you to start translations in your Android and iOS APPs.

Here are the most important workflows HowTo translate your text and HowTo add more supported languages.

(The app from the screenshots below is named ‘one_page_x’)

Workflow adding / editing translatable Strings

workflow_text_edited

Workflow supporting a new language

workflow_new_language

Cascades does it different

Doing x-platform apps also for BlackBerry 10 (C++/Qt 4.8/Cascades) it’s really easy:

Only add the languages to your project file (bar-descriptor.xml) …

cascades_add

… then build the project and all the lupdate/lrelease ts/qm stuff is done by magic under the hood:

cascades_ts_qm


← Back (Qt Creator – First Deployment)

→ Next Article (HowTo survive as a Qt Newbie)

⇐ Home (Overview / Topics)

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

Qt Quick Controls 2 are introduced as a Technical Preview in Qt 5.6 and willbecome Qt Quick Controls 2 in Qt 5.7.

Qt 5.7 Beta was announced 2016-04-21. This Beta is only available as a download – not from Online Installers.

If you only want to do first steps to try out you can go on with the Qt 5.6 – if you want to get the newest features it makes sense to install Qt 5.7 Beta.

Attention: the new UI Controls are still named ‘qt.labs.controls’ – beginning with the Qt 5.7 RC the renaming into Qt Quick Controls 2 will befinished, so be warned: you must change the imports in your QML files as soon as Qt 5.7 RC is out.

Besides Qt 5.7 Beta you’ll also get a new Qt Creator 4.0 RC.

Here are the steps to download and install Qt 5.7 Beta:

Install Qt 5.7 Beta

Go to your Qt Account – Downloads and select Qt – 5.7.0-beta:

01_download_01

Here’s my download on OSX:

01_download_02

Double click to install:

01_download_03

Log into your Account:

01_download_04

Select the folder where to install:

01_download_05

As next select your components:

01_download_06

and wait for the installer:

01_download_07

01_download_08

Start Qt Creator with -settingsPath

All Qt Creator instances by default share the settings. Having the new Qt Creator 4 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 and the new Qt 5.7 Beta.

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 Beta and do a right-click on the app. Here’s the content:

02_qtc_settings_01

rename Qt Creator to something like Qt Creator-bin:

02_qtc_settings_02

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

02_qtc_settings_03

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

02_qtc_settings_04

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

02_qtc_settings_05

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

Now you can start Qt Creator 3.6.1 from Qt 5.6.0 together with Qt Creator 4.0 RC from Qt 5.7 Beta without any collision.

Qt Creator 4.0 RC

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

03_qtc_flat_01

And here’s the new flat design:

03_qtc_flat_03

Qt Creator Preferences Working Directory

Set your working directory for 5.7 Beta:

04_qtc_workdir_01

Qt Creator Preferences Android

Take a look at your Android preferences:

05_qtc_android_01

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

05_qtc_android_02

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:

06_qtc_ext_tools_01

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:

06_qtc_ext_tools_02

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:

06_qtc_ext_tools_04

06_qtc_ext_tools_05

Test if Linguist will start. From External Tools

06_qtc_ext_tools_06

Linguist should start:

06_qtc_ext_tools_07

Verify Installation: New qt.labs.controls Project

As last step verify if all is correct configured. Normaly I do this using the qt.labs.controls Gallery app, but because of work on the renaming from qt.labs.controls into Qt Quick Controls 2 it’s missed as part of  Qt 5.7 Beta. So let’s try out a brand new qt.labs.controls Project wizard:

07_verify_installation_01

07_verify_installation_02

Select your Kits – I selected Android and iOS devices:

07_verify_installation_03

You’re done. Connect your device via USB and hit ‘Run’:

07_verify_installation_05

The app should run on your devices.


Congrats – now you have installed Qt 5.7 Beta. Please follow my blog series: https://appbus.wordpress.com/category/qt-for-mobile/overview/

As soon as Qt 5.7 RC is out I’ll edit the articles containing 5.6 screenshots.

Qt High DPI

Since Qt 5.6 HighDPI is supported for all platforms. All details here: http://blog.qt.io/blog/2016/01/26/high-dpi-support-in-qt-5-6/

Read more about Qt 5.6+ scalability: http://doc.qt.io/qt-5/scalability.html

Also new Qt Quick 2 Controls (qt.labs.controls in Qt 5.6) support High DPI : https://doc-snapshots.qt.io/qt5-5.6/qtlabscontrols-highdpi.html

Enable High DPI Support

To enable High DPI Support you must enable Qt::AA_EnableHighDpiScaling :

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // <--
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

Device Pixel Ratio (Scaling Factor)

In Qt from display density (dpi) a scaling factor was calculated, where 160 dpi is scaling factor 1.

You can easy test this for your devices:

	qDebug() << qApp->primaryScreen()->devicePixelRatio();

For my two devices I got:

  • Android (PRIV), 540 dpi –> scaling factor: 3.5
  • iOS (iPhone 6S), 326 dpi –> scaling factor: 2.0

Use Pixels in QML

UI is defined in QML and all sizes, coordinates, … are in pixels. This is how Qt worked all the 20+ years.

Now with High DPI enabled the pixels are density-independent. Let’s take a look at the iPhone with Device Pixel Ratio 2.0

iPhone 6S has 750 x 1334 with 326 dpi. Let’s check the size:

	qDebug() << qApp->primaryScreen()->size();
	// we get: QSize(375, 667)

we get 375 x 667. So using a width of 120 will be calculated as 120 * 2.0 = 240 px

let’s compare this with other platforms:

Android Device Independent Pixels (dip / dp)

Android does it similar: Device Independent Pixels are 1:1 for 160 dpi (mdpi)

Android uses a set of generalized densities:

  • ldpi (low) ~120dpi –> scaling factor: 0.7
  • mdpi (medium) ~160dpi –> scaling factor: 1.0
  • hdpi (high) ~240dpi –> scaling factor: 1.5
  • xhdpi (extra-high) ~320dpi –> scaling factor: 2.0
  • xxhdpi (extra-extra-high) ~480dpi –> scaling factor: 3.0
  • xxxhdpi (extra-extra-extra-high) ~640dpi –> scaling factor: 4.0

Read more in detail here: http://developer.android.com/guide/practices/screens_support.html

As you can see Android also has a baseline at 160 dpi, so it’s the same as with Qt.

iOS Points and Pixels

What about iOS ? Coordinates and sizes are defined in points.

And it’s the same as for Android and Qt: At a density of 160 dpi the scaling factor is 1.

Take a look at http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions to compare all the sizes, pixels and points.

As you can see the iPhone 6 has 375 x 667 points for 750 x 1334 pixels – same as with Qt.

BlackBerry 10 Design Units (du)

Since OS 10.3 BlackBerry 10 also is resolution independent: https://developer.blackberry.com/native/documentation/best_practices/resolution/

BB10 uses Design Units (du) and groups the devices:

  • BlackBerry Classic (720×720), 294 dpi –> 8 pixel per du
  • BlackBerry Z30 (720 x 1280), 295 dpi –> 8 pixel per du
  • BlackBerry Passport (1440 x 1440), 453 dpi –> 12 pixel per du

Coming from BlackBerry 10 development, you have to rethink / recalculate your dimensions.

There will be more articles about Icons, Images, Orientation, … stay tuned


← Back (Qt Quick Controls 2)

→ Next Article (Our first demo app)

⇐ Home (Overview / Topics)


 

Qt for Mobile Business Apps

I want to motivate other mobile APP developers to try out Qt for mobile and decided to publish a blog series. If you are an Android, BlackBerry 10 or iOS developer these articles are for you ! See also the Video about Qt – x-platform development at the bottom of this page if you need an appetizer.

 

Video MobileTechCon 2016 Munich

My talk at MobileTechCon gives you a first overview and explains in detail why I – besides BlackBerry 10 – am using Qt 5.6+ for native x-platform development.

 

Patch Qt 5.6.0

April 8, 2016 — Leave a comment

While testing Qt 5.6.0 and qt.labs.controls on Android and iOS I noticed a problem.

Please take a look at this screenshot:

01_textfield

qt.labs.controls provide three styles: Material, Universal, Default. Controls are different but should have similar size.

As you can see the text in Material style is too small. So I reported a bug: https://bugreports.qt.io/browse/QTBUG-50971

Bug was fixed soon by J-P Nurmi:)

02_bugfixed

As I reported the bug, branch 5.6.0 was already freezed, so the fix is in current 5.6 branch: 5.6.1

If you installed 5.6 you probably got 5.6.0.

You can verify your version from Qt Creator –> Preferences –> Build & Run –> Qt Versions

03_my_version

If you want to do some real apps from Qt 5.6.0 you should patch your installed Qt Version.

Qt is Open Source – so it’s no problem to get the changed module:)

From the bug you can get the info of the affected component (qt/qtquickcontrols2) and the branch (5.6) where it was fixed:

04_component_branch

Now it’s easy to patch.

Hint: you must do this for all installed kits – so I have done it for Android and iOS.

Open a Terminal and do this to patch the Android Kit:

export ANDROID_NDK_ROOT=/your_path_to/android-ndk-r10e
cd /your-path-to-store-cloned-repo_android
git clone --branch 5.6 git://code.qt.io/qt/qtquickcontrols2.git
cd qtquickcontrols2
/your-path-where-qt-is-installed/5.6/android_armv7/bin/qmake
make
make install

and similar for iOS:

cd /your-path-to-store-cloned-repo_ios
git clone --branch 5.6 git://code.qt.io/qt/qtquickcontrols2.git
cd qtquickcontrols2
/your-path-where-qt-is-installed/5.6/ios/bin/qmake
make
make install

thanks @jpnurmi helping me to make this work.


← Back (Install Qt 5.6)

→ Next Article (Qt Creator – Intro)

⇐ Home (Overview / Topics)


Edited 2016-04-28: Unfortunately Qt 5.7 Beta doesn’t include the Gallery because of some renaming-trouble. To test a first deployment running Qt 5.7 Beta please follow this article: qt-5.7-beta


Now it’s time to check if your installation and settings are well done. Easiest way to do this is to deploy an existing example to Android and iOS.

qt.labs.controls Gallery Example

Open Qt Creator, then goto Welcome –> Examples and search for labs.controls: (Qt 5.6) or search for Gallery from Qt 5.7

01_first_deploy

In 5.6 where qt.labs.controls are only a TechPreview there’s only one Example: Gallery

Build and Run Configuration

Click on Gallery selects ‘Project’ on the left side and opens two windows: Project Build and Help:

02_first_deploy

Click on Add Kit to add your Kits:

03_first_deploy

I always only test on real devices, so I’m using these two Kits: Android for arm and iPhone.

04_first_deploy

Hover with your mouse over the top-right corner of a Kit and you can Remove it.

Each Kit has Build and Run Tabs where you can configure the build. Qt Creator should have done most of the work automatically – so for running the Example it should work out of the box.

Here’s the Android Build:

05_first_deploy

check the APK Build, where you can select the SDK. Also there’s the checkbox to use Gradle and how Qt libraries are bundled:

06_first_deploy

Compile, Deploy and Run on Android

Now connect your Android Phone via USB.

At left-bottom side please select the correct Kit to be used: Android – Debug:

07_first_deploy

Now we can (Build and) Run the APP:

08_first_deploy

Qt Creator asks you which Device to use. We already have connected the Android Device: STV100-4 is the BlackBerry PRIV:

09_first_deploy

Select the Device and Qt Creator will compile and build. Open the Compile Output to see what happens:

10_first_deploy

As next the APP was deployed to the Device and started. You can verify the Console output from ‘Application Output’.

priv

Compile, Deploy and Run on iOS

Now we want to do the same for iOS.

Connect your iPhone via USB and again select the right Kit:

11_first_deploy

This time there’s no extra Dialog to select the Device – it’s on top of Kit Selection. iPhone and Debug are selected – so we can Run again.

Project compiles, deploys and runs the APP on iPhone.

12_first_deploy

13_first_deploy

iphone

Go through this Gallery Example to see most of UI and Navigation Controls in Action.

From Settings you can switch between Material, Universal and  Default.


← Back (Qt Creator – Settings)

→ Next Article (HowTo Translations (i18n))

⇐ Home (Overview / Topics)