jeudi 26 janvier 2012

Qt quick components Symbian : combiner TabBar et PageStack

Bonjour,
Aujourd'hui je vais vous présenter un exemple de code définissant un squelette d'application Qt basée sur les composants Qt Quick et combinant les contrôles TabBar (barre à onglets) et PageStack (empilement de page). Le rendu sera le suivant :



Comme vous pouvez le constater, l'application est composée (de bas en haut) :
  • une barre de status
  • une bannière
  • une barre à deux onglets
  • une page contenant un libellé et un bouton
  • une barre d'outils
L'expérience utilisateur est la suivante :
  • si je clique sur la flèche en bas à gauche, je quitte l'application car la profondeur de la pile de pages est de 1
  • si je clique sur le bouton "Go to Page 1.1", j'affiche une nouvelle page tout en restant sur l'onglet "Tab 1" ; cet onglet contiendra alors une pile de pages de profondeur 2 :


Note : si je clique sur la flèche "retour", je retournerai à la page précédente tout en restant sur     l'onglet Tab1
  • si je clique sur le bouton "Go to Page 1.2", j'affiche une nouvelle page tout en restant sur l'onglet "Tab 1" ; cet onglet contiendra alors une pile de pages de profondeur 3 :

Pour revenir à la page initiale 1.0, il y a deux options : soit je clique sur l'onglet "Tab1" lui-même, soit je clique successivement deux fois sur la flèche "retour".
  • enfin si je clique sur l'onglet "Tab2", j'affiche une simple page :


Note : si je clique sur "retour", l'application se termine car la pile de page ne contient qu'une seule page.

Regardons maintenant le code de plus près ... J'ai crée un projet Qt quick sous Qt Creator basé sur l'utilisation des composants Qt Quick pour symbian. Le projet sera constitué de 5 fichiers QML :
  • fichier main.qml définissant visuellement le squelette de l'application avec la barre de status, la bannière, les onglets et la barre d'outils
  • fichier splashscreen.qml affichant une image au lancement
  • fichier Page1_0.qml définissant la première page de l'onglet 1
  • fichier Page1_1.qml définissant la seconde page de l'onglet 1
  • fichier Page1_2.qml définissant la troisième et dernière page de l'onglet 1
Note : la définition de l'unique page de l'onglet n°2 sera embarquée dans le fichier main.qml.

Fichier main.qml

J'ai créé une barre de status car le contenu de l'application ne nécessite pas une immersion totale comme cela peut être le cas avec un player video :

Window{
    id: rootWindow

    property Item mySplashscreen;
    property int zOrder:12;


        // Barre de status masquée par défaut
    StatusBar {
        id:statusbar
        anchors.top: parent.top
        z:zOrder
        visible:false
    }
 
Cette barre de status est masquée par défaut le temps d'afficher le splashscreen en plain écran. Par ailleurs j'ai donné une profondeur importante (facteur z) de manière à assurer qu'aucun composant puisse masquer cette barre. Ensuite j'ai défini une bannière placer sous la barre de status :

// Bannière d'entête masquée par défaut
Image{
    id: header
    anchors {
        left: parent.left
        right: parent.right
        top: statusbar.bottom
    }
    source: "header.png"
    width:360
    height:49
    z:zOrder
    visible:false
}


Dans une véritable application, cette bannière pourra représenter une marque ou une bannière de publicité. Puis j'ai défini une barre avec deux onglets :


// Barre d'onglets (Tabbar) contenant trois onglets dans notre cas
TabBarLayout {
     id: tabBarLayout
     anchors {
         left: parent.left
         right: parent.right
         top: header.bottom
     }
     z: zOrder
     visible: false
     TabButton { tab: tab1; text: "Tab1"; onClicked: tab1.pop(null)}
     TabButton { tab: tab2; text: "Tab2" }
 }

 // Définition du contenu de chaque onglet
 TabGroup {
     id: tabGroup
     anchors {
         top: tabBarLayout.bottom
         left: parent.left
         right: parent.right
         bottom: parent.bottom
     }

     // Onglet n°1 contenant une pagestask
     PageStack {
         id: tab1

         initialPage: Page1_0 {tools: toolBarLayout1}

         ToolBar {
             id: myToolBar1
             anchors.bottom: parent.bottom
             tools:toolBarLayout1
             z:zOrder
         }

         ToolBarLayout {
             id: toolBarLayout1
             ToolButton {
                 flat: true
                 iconSource: "toolbar-back"
                 onClicked: {
                     if(tab1.depth <= 1) Qt.quit()
                     else
                         tab1.pop()
                 }
             }
         }
     }

     // Onglet n°2 contenant une simple page
     Page {
         id: tab2
         anchors.fill: parent

         Rectangle
         {
             color:"darkgreen"
             anchors.fill: parent
             Text {
                 id:title
                 anchors.centerIn: parent
                 text: "Simple page"
                 color: "white"
             }

         }

         tools: toolBarLayout2

         ToolBar {
             id:myToolBar2
             anchors.bottom: parent.bottom
             tools:toolBarLayout2
             z:zOrder
         }

         ToolBarLayout {
             id: toolBarLayout2
             ToolButton {
                 flat: true
                 iconSource: "toolbar-back"
                 onClicked: Qt.quit()
             }
         }
     }
  }
 
Comme vous pouvez le constater, le premier onglet "tab1" est représenté par une pile de pages (composant PageStack) dont la page initiale est définie dans un autre fichier (Page1_0.qml) tandis que le second onglet "tab2" est représenté par une simple page définie en ligne. C'est un choix délibéré afin de vous montrer qu'il est possible de gérer différents types de contenu par onglet. Par ailleurs chaque "contenant" d'onglet disposera d'une barre d'outils constituée d'un bouton de retour. Dans le cas d'une pile de pages, un clic sur "retour" permettra de dépiler la pile afin d'afficher la page précédente. Dans le cas d'une page simple, le même clic aura pour effet de quitter l'application. Dernier point : noter la présense d'un slot "onclicked" pour le premier TabButton : tab1.pop(null). Celui-ci permet de dépiler toute la pile afin de retourner à la page racine.

Component.onCompleted:
{
    // Création et affichage du splashscreen
    var component = Qt.createComponent(Qt.resolvedUrl("Splashscreen.qml"));
    if (component.status == Component.Ready)
    {
        mySplashscreen = component.createObject(rootWindow);
    }
}


Une fois la page principale chargée, je crée dynamiquement le splashscreen dont nous gardons une instance dans la propriété mySplashscreen. Enfin j'initialise un timer de 3 secondes, durée d'affichage du splashscreen :

// Définit la durée d'affichage du splashscreen (3s)
Timer {
      interval: 3000;
      running: true;
      onTriggered:
      {
          mySplashscreen.visible = false
          tabBarLayout.visible = true
          statusbar.visible = true
          header.visible = true
      }
}


Sur expiration du timer, je masque le splashscreen et je rends visible la bannière, la barre de status et la barre d'onglets.

Le code complet est disponible ici.

1 commentaire:

  1. Salut Geronimux, j'ai pas trouvé d'autre moyen de te contacter autre que ce commentaire.
    Je suis en train de faire faire un planetqt.fr , qui regroupe tous les flux de blog parlant de qt, à l'instar de planetqt.org, mais en francais .
    Est ce que je peux ajouter ton blog à la liste de flux ?

    RépondreSupprimer