Ajoutez un splashscreen à votre application avec QT5 et QML

Afin d’égayer le chargement des applications qui prennent un certain temps à se lancer, les développeurs ont souvent recours à un « splash screen », un écran de démarrage qui est affiché pendant le lancement et l’initialisation de l’application. Le splashscreen peut afficher et mettre en valeur le logo et le nom de l’application, afficher une barre de progressions, le ou les noms du ou des développeurs, et il permet surtout d’afficher un retour à l’utilisateur, de le faire patienter et de lui montrer que tout est sous contrôle.

Dans le cadre de mon projet Touchradio, j’ai ainsi été amené à mettre en place ce genre de mécanisme durant le démarrage de l’application, le chargement des ressources, la connection au server,… Dans la suite de cet article, je vais expliquer comment j’y suis parvenu en utilisant QT5 et QML, avec le projet d’exemple en prime!

La technique que j’ai utilisée est la suivante:

l’application est encapsulée dans une classe ‘MyApplication’. Cette classe dérive de QObject, ce qui permet d’utiliser le mécanisme des signaux et slots si cher à QT.
au lancement de l’application, un premier fichier QML (splash.qml) est chargé. Ce fichier affiche un message à l’utilisateur l’invitant à patienter pendant le chargement du programme.
lorsque ce fichier QML est complètement chargé, il appelle le slot ‘init()’ de l’application. La méthode derrière ce slot implémente toute l’initialisation de l’application: chargement des ressources, initialisation des objets et variables, connection au server,…
une fois que cette méthode est terminé, le fichier splash.qml va charger et afficher le fichier main.qml, qui est le fichier QML principal de l’application

Cette manière de faire est bien différente que l’idée que je m’en faisais au départ. J’ai essayé d’utiliser des threads, par exemple, mais cela n’était pas approprié pour QT.

Voici quelques extraits du code source:

Fichier main.cpp

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickView viewer;

    /* Instantiate the application class */
    MyApplication* myApp = new MyApplication(&viewer);

    /* Run, baby run! */
    myApp->start();

    /* Call the QT event loop */
    return app.exec();
}

Plus simple que ça, tu meurs! Logique, toute l’intelligence se trouve dans la classe MyApplication: myapplication.h

class MyApplication : public QObject
{
    Q_OBJECT
public:
    MyApplication(QQuickView* viewer);
    void start();

public slots:
    void init();

private :
    QQuickView* viewer;
};

L’interface de cette classe est très simple elle aussi: un constructeur à qui on passe le QQuickView dans lequel elle va charger ses fichier QML, une méthode start() (appelée depuis le main()), et un slot init() (appelée depuis le fichier QML splash.QML).

L’implémentation de cette classe : myapplication.cpp

MyApplication::MyApplication(QQuickView* viewer)
{
    this->viewer = viewer;
}

void MyApplication::start()
{
    // Search for the directory of the executable file
    QDir directory(QCoreApplication::applicationDirPath());

    // Build the path to the splash.qml file
    QString path = directory.absoluteFilePath("../qml/Splashscreen/splash.qml");

    // Give a reference to this object to the splash.qml file. This will
    // allow it to call the method init()
    this->viewer->engine()->rootContext()->setContextProperty("myapplication", this);

    // Load splash.qml
    this->viewer->setSource(QUrl::fromLocalFile(path));

    // And display it
    this->viewer->show();
}


void MyApplication::init()
{
    // Add any initialization instruction here.

    QThread::msleep(5000); // Blocks (sleeps) during 5 seconds
}

Le plus intéressant ici, c’est le méthode MyApplication::Start(). Cette méthode commence donc par charger le fichier splash.qml en lui donner une référence vers… l’instance de MyApplication (this). Cela permettra au fichier QML d’appeler le slot MyApplication::init(). Cette méthode, comme vous pouvez le voir, doit contenir toute l’implémentation de l’initialisation de l’application, qui peut durer un certains temps.

Enfin, le fichier splash.QML :

import QtQuick 2.0


Item {
    id: root

    // Display a little message to the user while loading...
    // ...

    // This is the Loader that will load the main.qml file
    Loader {
        id: main
        anchors.fill: parent
        asynchronous: true
        visible: status == Loader.Ready
    }

    // This is a fake delay needed to give to QML the necessary time
    // to load and setup the splash item above
    PauseAnimation {
        id: fakeLoadingDelay
        duration: 50
        onRunningChanged: {
            if ( !running ) {
                // Call the init() function of myapplication
                myapplication.init();

                // When the init() returns, load main.qml
                main.source = "main.qml"
            }
        }
    }

    // This start the animation and loading of mail.qml when the component is ready
    Component.onCompleted: fakeLoadingDelay.start()
}

Donc, on attends que le fichier soit complètement chargé (avec l’évènement Component.onCompleted). Cet évènement va lancer l’animation fakeLoadingDelay, qui va enfin exécuter, après un petit délai, la méthode myapplication.init(). Il s’agit d’une méthode bloquante, mais cela ne pose pas de problème car le splashscreen est déjà affiché. Enfin, quand cette méthode retournera le contrôle au fichier qml, le fichier main.qml va être chargé en lieu et place du fichier splash.qml.

Le projet complet est disponible sur mon compte GitHub.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *