Add a splashscreen to your application with QT5 and QML

In order to make the loading of their application more confortable, software developper often add a splashscreen, a window that is displayed while the softawre is loading and initializing. The splashscreen may display a logo, the name of the software, a progress bar, the name of the softawre developper(s),… Most of all, the splashscreen gives a feedback to the user, make him wait while loading, and demonstrate him that everything is under control.

I needed such a thing in my project Touchradio, because, the initialization of the softawre takes quite a long time (yes, 5 seconds is too much for the average user), because it needs to load ressources, initalize objects, connect to the server,… In this post, I’ll explain how I manage to implement it in QT5 and QML. And, as a gift, I’ll give you the full source code of the example!

Here is how I proceed:

the application is encapsulated in a class ‘MyApplication’. This class derives from QObject, which allows it to use the well-know mecanism from QT : signals and slots
when the application is starting, a first QML file (splash.qml) is loaded. This file displays a message to the user, asking him to be patient while the software is starting
when this file is completely loaded and displayed, it call the slot ‘init()’ from the application. This is where the very long initialization of the application takes part
once this method returns, the file splash.qml loads and displays the main QML file of the application : main.qml.

This procedure is fare different from my first idea, but it seems to be very adapted to QT.

Here are some excerpts from the source code:

File 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();
}

Quite simple, isn’t it… that’s because everything is hiddent the the class MyApplication : myapplication.h

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

public slots:
    void init();

private :
    QQuickView* viewer;
};

The interface of this class is very simple too : a constructor which receives a QQuickView in which the application will load its QML files, a start() method (which is called from main()) and the slot init(), which is called from the QML file ‘splash.qml’).

The implementation of this class : 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
}

The most interesting part here is the method MyApplication::start(). This method begins with loading the file splash.qml and by giving it a reference to… itself (this). This will allow the QML file to call the slot MyApplication::init() of this instance. As you can see, this method contains all the implementation of the initializatin of the application, which can last for a long time.

Finally, the file 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()
}

So, we wait for the file to be completely loaded (thanks to the event Component.onCompleted). This event will launch the animation fakeLoadingDelay, which, after a little delay, will call the method myapplication.init(). This is a blocking method, but it’s no problem, because, the splashscreen is already loaded and displayed. Finally, when this method returns, the file main.qml will be loaded and displayed in place of the splashscreen.

The complete example project is available on my Github page.

Leave a Reply

Your email address will not be published. Required fields are marked *