Sami Makkonen

How to Create Qt Applications with Metro Style

1/25/2012 5:54 PM  | Posted by: Sami Makkonen

As the Deploying on Windows 8 Tablets with Qt Commercial blog post demonstrated, the Qt Commercial C++ and Qt Quick applications ran nicely without any problems or modifications on Windows 8 Developer Preview. With this post we are going to show in more detail how Qt applications can be styled to follow the Metro style. The examples are normal Qt applications styled to look similar to Metro application.

 

Metro is the name of the new user interface design language created by Microsoft. Currently Metro is used as a basis for the Windows Phone 7 and later on will serve as the basis for the Windows 8 UI. To reach the essence of the Metro style, we are going to style the Qt applications by using general Metro UI styling and design principles.

 

As said in Microsoft's general design principles guide, Metro style focuses strongly on content. Metro is designed to be simple and light, free of chrome elements, where the content is the interface. Key design principles along with previous ones are consistency, typography and motion. To bring consistent structure to UI, all the UI items are separated from each other's by using consistent margins and items are usually aligned evenly to the left. Metro relies heavily on text and typography. Plain text is used not only to show the content but as a marker leading to more content. Font type is from (depending on the platform) Segoe - font family and font sizes are consistent depending on the usage (certain size for headers etc.). Metro doesn’t support text clipping or fading; instead every text unfitting to the screen is flushed to the right, over the screen. As mentioned, one of the key elements of Metro is the motion. By motion they mean animations to user actions, like visual feedback of pushing a button or view transition. Transitions should also be consistent, giving the same kind of feedback for the same kind of actions.

 

So there we go. We have few key elements of the Metro design outlined. To demonstrate how Qt Commercial can be used for catching the Metro style essence, we created two simple applications: grid view application with QML and pivot control application with Qt C++.

 

Creating Metro styled grid view with QML

The grid view example demonstrates how the QML components can be used to create Metro styled grid application, similar to the Windows 8 developer preview live tile starting screen.

 

The live tile starting screen consists of header and grid view below it. Grid view is aligned to the left and it flows over the right side. The grid can be kinetically panned left or right and the application can be started by tapping the tiles. To follow the design principles stated in previous chapter, simple style settings were defined for the UI components.

 

  1. property int topBarSize: 144
  2. property int barSize: 120
  3. property int tileMargin: 12
  4. property int tileHeaderFontSize: 11
  5. property int tileDateFontSize: 10
  6. property int appHeaderFontSize: 36
  7. property string appBackground: "#262626"
  8. property string tileBackground: "#86bc24"
  9. property string textColor: "white"
  10. property string uiFont: "Segoe UI"
  • file: main.qml

The style settings define the structure, colors and fonts for the application UI. As you can see the topBarSize, barSize and tileMargin are 12px or 12px increments to make the layout consistent. The font type is set to Segoe UI. As the style is defined, the UI structure needs to be defined. Note that we are not going through all the source code, only the essential lines for the UI.

  1. // Top bar
  2. Rectangle {
  3.     id: topBar
  4.     anchors.left: leftBar.right
  5.     anchors.top: parent.top
  6.     height: topBarSize
  7.     color: appBackground
  8.     Text {
  9.         ...
  10.         text: qsTr("Qt Commercial Blog")
  11.         font.family: uiFont;
  12.         font.pointSize: appHeaderFontSize;
  13.         color: textColor
  14.     }
  15. }
  16.  
  17. // left bar
  18. Rectangle {
  19.     id: leftBar
  20.     anchors.left: parent.left
  21.     anchors.top: parent.top
  22.     width: barSize
  23.     height: parent.height
  24.     color: appBackground
  25.     ...
  26. }
  27.  
  28. // Grid view
  29. GridView {
  30.     id: grid
  31.     anchors.left: leftBar.right
  32.     anchors.top: topBar.bottom
  33.     flow: GridView.TopToBottom
  34.     width: parent.width - leftBar.width
  35.     height: parent.height - topBar.height - bottomBar.height
  36.     cellHeight: parseInt(grid.height / 3)
  37.     cellWidth: parseInt(cellHeight * 1.5)
  38.     clip: false
  39.     model: feedModel
  40.     delegate: RssDelegate {}
  41.     ...
  42. }
  43.  
  44. // bottom bar
  45. Rectangle {
  46.     id: bottomBar
  47.     anchors.top: grid.bottom
  48.     anchors.left: leftBar.right
  49.     width: parent.width - leftBar.width
  50.     height: barSize
  51.     color: appBackground
  52.     ...
  53. }
  • file: main.qml

The UI structure is quite simple. It consists of a top bar, left bar, bottom bar and the grid view center styled with defined style settings. The GridView is a standard QML component for displaying items in the grid layout. GridView allows items to be laid out horizontally and item sizes can be defined by using cellHeight- and cellWidth – properties. Clipping is set to false, which allows the grid to be moved left or right “over” the screen. GridView supports also kinetic panning with appropriate easing by default. The content for the grid view is from the Qt Commercial RSS feed fetched by using XmlListModel.

 

That’s it. The QML grid application is styled to follow Metro. Check the result from the demo at the end of this post.

 

Creating pivot control with Qt C++

With the second example we are going to show how to implement and style Metro pivot control with Qt C++. The pivot control is a Metro version of the normal tab control with some exceptions. It allows multiple pages to be defined for the same window and each page consists of a certain type of information or other controls. Pivot header items flow over the screen to the right and the selected item is always moved to the left of the screen.

 

For the building blocks of the application we decided to use the QGraphicsView and QGraphicsTextItem classes. Similar to the previous example, simple style settings were defined for the UI.

 

  1. const int componentMargin = 24;
  2. const int bodyTextSize = 24;
  3. const int headerTextSize = 48;
  4. const QFont headerFont = QFont("Segoe UI", headerTextSize);
  5. const QFont bodyFont = QFont("Segoe UI", bodyTextSize);
  6. const QColor uiTextColor = Qt::white;
  7. const QString backgroundStyle = "background-color: rgba(26,26,26)";
  8. const int animationTime = 400;
  • file: Style.h

 

The componentMargin defines consistent margin for all the UI components horizontally and vertically. The font is set to Segoe UI. The following code snippet demonstrates the creation of pivot header items.

 

  1. ...
  2. const int itemCount = 6;
  3. ...
  4. QGraphicsTextItem *tmp;
  5. ...
  6. for(int i = 0; i < itemCount; ++i) {
  7.     tmp = new QGraphicsTextItem();
  8.     text = "loremIpsum";
  9.     text = text.append(QString("%1").arg(i+1));
  10.     tmp->setPlainText(text);
  11.     tmp->setFont(headerFont);
  12.     tmp->adjustSize();
  13.     tmp->setDefaultTextColor(uiTextColor);
  14.     // below header text
  15.     tmp->setPos(xPos,(componentMargin * 2 + bodyTextSize));
  16.     // calculate the position for the next item. ComponentMargin // + item width + ComponentMargin
  17.     xPos = xPos + tmp->textWidth() + componentMargin;
  18.     ...
  19.     mHeaderItems.append(tmp);
  20.     scene()->addItem(tmp);
  21. }
  • file: tabview.cpp

As the snippets show, 6 pivot control header items are created. For each header item there needs to be content. In this case the content is text so the QGraphicsTextItem was also used for showing it. Since the QGraphicsTextItem is used in header and content items the creation of content items is similar to the creation of header items. The difference is that the bodyFont is used as a font and position is set to be below header items.

For bringing the motion to the UI via animations, the QPropertyAnimation class was used. The following code snippet demonstrates the creation of the animation item.

 

  1. ...
  2. QPropertyAnimation *anim;
  3. anim = new QPropertyAnimation(tmp, "pos");
  4. anim->setDuration(animationTime);
  5. anim->setPropertyName("pos");
  6. anim->setEasingCurve(QEasingCurve::OutCirc);
  7. mGroupAnimHeader->addAnimation(anim);
  8. mHeaderAnimations.append(anim);
  9. ...
  10. mHeaderItems.append(tmp);
  11. scene()->addItem(tmp);
  • file: TabView.cpp

 

Metro UI style recommends using two types of ease for the animations; logarithmic for the object entering to the screen and exponential for the object leaving the screen. In this case the Qt's QEasingCurve::OutCirc is used for both. It provides logarithmic-like ease to the animation. The following code snippet demonstrates the usage of animations.

 

  1. void TabView::mouseMoveEvent(QMouseEvent *event)
  2. {
  3.     int xDif = event->pos().x() - mMouseXPosition;
  4.     ...
  5.     if(xDif < 0) {
  6.         ...
  7.         startContentAnimation(ESweepLeft);
  8.         startHeaderAnimation(ESweepLeft);
  9.     } else if(xDif > 0) {
  10.         ...
  11.         startContentAnimation(ESweepRight);
  12.         startHeaderAnimation(ESweepRight);
  13.     }
  14.     mMouseXPosition = event->pos().x();
  15. }
  1. void TabView::startContentAnimation(int direction)
  2. {
  3.     QPropertyAnimation *anim;
  4.     QGraphicsTextItem *text;
  5.     // init animation items
  6.     for(int i = 0; i < itemCount; ++i) {
  7.         text = mContentItems.at(i);
  8.         anim = mContentAnimations.at(i);
  9.         QPointF start = text->pos();
  10.         QPointF end = start;
  11.         if(direction == ESweepLeft)
  12.             end.setX( end.x() - text->textWidth() - componentMargin);
  13.         else
  14.             end.setX( end.x() + text->textWidth() + componentMargin);
  15.         anim->setStartValue(start);
  16.         anim->setEndValue(end);
  17.     }
  18.     mGroupAnimContent->start();
  19. }
  • file: TabView.cpp

 

The animation is started for the pivot and content items when the screen is swiped left or right. Sweep is detected in the mouseMoveEvent-function and each time a new animation starts and ends, points are calculated depending on the direction of sweep. Pivot items opacity is set to 0.6, if not highlighted. Highlighted item's opacity is set to 1.0 by using linear easing during the animations.

 

To sum up, we now have a pivot control constructed by using the QGraphicsTextItem - classes and also a nice transition effect between views by using QPropertyAnimation - class.

 

Check out the results in the following video as well as the sample code here.

 

 

Comments:

Cc | 1/27/2012 5:31 PM
That's nice, but it's just faking the Metro style. Will we be ever able to write real Metro apps with Qt, i.e. apps running on top of WinRT?

Jawani | 3/3/2012 7:53 AM
you can RSVP to or just leave it here and i'll add you in I know it's too late for this party, but just for future rcnerefee.

Tags

Archive

Authors

Pasi Matilainen

Pasi is a Software Specialist working at Digia, Qt Commercial R&D and he concentrates on Mac OS X development. Pasi holds an M.Sc. degree in Information Technology from the Tampere University of Technology, Finland.

Tarja Sundqvist

Tarja is a Senior Software Engineer in the Digia, Qt Commercial Support team. She has been working in Digia for over 10 years in various positions: software development, testing, error management. Now, Tarja is focusing on helping Qt Commercial customers with their daily Qt problems on Windows and Linux platforms. Tarja holds an M.Sc. degree in Information Processing Science from the University of Oulu, Finland.

Akseli Salovaara

Akseli is a Software Specialist at Digia, Qt Commercial R&D and is responsible for the Qt Commercial releases and deliveries. Akseli holds an B.Sc. degree in Information Technology from the University of Applied Sciences in Jyväskylä, Finland.

Samuli Piippo

Samuli is a Software Specialist at Digia, Qt Commercial R&D with a concentration on  embedded Linux and RTOS development. Samuli holds an M.Sc. degree in Information Processing Science from the University of Oulu, Finland.

Katherine Barrios

Katherine is the Marketing Manager at Digia, Qt Commercial. She is responsible for getting the word out about Qt Commercial to the Qt ecosystem and working together with our customers and the Qt community to further extend the love for Qt on desktop and embedded. She was previously employed at Nokia, Qt Development Frameworks as Program Marketing Manager and is based in Oslo, Norway.

Sami Makkonen

Sami is a Senior Product Manager working at Digia, Qt Commercial R&D and he is responsible for the product planning including new feature development and enhancements to existing functionality. Sami holds an M.Sc.(Econ.) degree in Computer Science.

Andy Shaw

Andy is the Head of Support at Digia, Qt Commercial and has been working with Qt and supporting customers using Qt for 11 years.  He thrives on solving customer problems and getting feedback from them.

Tuukka Turunen

Tuukka is the Director of R&D at Digia, Qt Commercial and is responsible for the planning, creation, verification and delivery of the Qt Commercial product. Tuukka holds a M.Sc.(Eng) and Licentiate of Technology degrees in Computer Science.

Qt Commercial Team