Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Splashscreen during initialization



  • Hi,

    I'm working on an application which has a quite long initialization procedure (connect to a server, get data from the server, load QML files, images,...).

    I would like to display another QML file (a splashscreen) during the initialization of the application.

    I tried this:
    *

    • Create an QGuiApplication and a QQuickView objects
    • call SetSource() on QQuickView to load the splashscreen QML file and then show()
    • start a QThread that will run the init procedure
    • call the method exec() of the QGuiApplication object.
    • when the thread is finished, call SetSource() on the QQuickView again to make it load the final QML file.

    By doing this, I expect that the application is running, and that the splashscreen is displayed during the execution of the thread but... It's not the case.

    For testing, the initialization thread only call msleep() so, it does nothing

    During the execution of the thread, a blank window is opened, it doesn't display the splashscreen (ConnectingDialog.qml).
    It's only when the thread exits that the windows is updated with the content of the main QML file.

    ConnectingDialog.qml is a simple module that displays a black rectangle with some text

    Here is my code:
    Some declarations:
    @
    QGuiApplication* app;
    QThread* startThread;
    QQuickView* viewer;
    @

    The Start() function of the application
    @
    int MyApp::Start()
    {
    QDir directory(QCoreApplication::applicationDirPath());
    QString path = directory.absoluteFilePath("qml/ConnectingDialog.qml");

    viewer->setSource(QUrl::fromLocalFile(path));
    viewer->show();
    
    this->connect(this->startThread, SIGNAL(started()), SLOT(RunStartSequence()));
    this->connect(this, SIGNAL(finished()), SLOT(OnStartSequenceFinished()));
    this->startThread->start();
    return 0;
    

    }
    @

    The function called by the startThread:
    @
    void MyApp::RunStartSequence()
    {
    this->startThread->msleep(5000);
    emit finished();
    }
    @

    And the slot OnStartSequenceFinished():
    @
    void MyApp::OnStartSequenceFinished()
    {
    QDir directory(QCoreApplication::applicationDirPath());
    QString path = directory.absoluteFilePath("qml/main.qml");

    viewer->setSource(QUrl::fromLocalFile(path));
    

    }
    @

    main()
    @
    QGuiApplication app(argc, argv);
    MyApp myApp;

    myApp.Start();
    return app.exec();
    

    @

    I don't understand why my splashscreen is not displayed during the execution of the init thread.
    Can you help me?

    Thanks in advance!



  • Ok, I think I've found why it's not working as expected.

    With the code from my previous post, RunStartSequence() is executed into the same Thread as the function Start(). That's why the display is not updated during the execution of RunStartSequence().

    It seems that threads in QT do not work as I expected them to work. I'll have to read the documentation more carefully.
    I manage to make it work by using examples from "here.":http://qt-project.org/doc/qt-5.0/qtcore/qthread.html

    So, the example with msleep() is working, but I got into other issues: in my init function, I use object which were created in other threads,... And I get a lot of error messages.

    I think I'll implement my splashscreen in another way ("example":http://developer.nokia.com/Community/Wiki/Splash_screen_while_loading_main_qml )



  • Mhm... I can't find a solution for my issue...
    At first, it seemed easy but... it's not.

    So, how would you do this in QT5/QML?

    • Just after the application starts, display the content of a QML file ("Please wait while connecting to the server...", for example).
    • When the message is displayed, do all the initialization stuffs that take a long time (connect to a server, get data from the server, create objects that will be used by the QML application,...). The init is done in C++.
    • When everything is ready, load another QML file that will use objects that were created during init.

    Thanks for your help!



  • After a good night of sleep... I still cannot find a solution :/

    I found this "example":http://developer.nokia.com/Community/Wiki/Implementing_a_Splash_Screen_with_Qt_Quick but

    • It's a QT4 example, and some objects/methods do not exist anymore in Qt5
    • I don't understand how this could work, as the UI is updated only when calling app.exec().
    • In this example, where is app.exec() called?

    My main problem : I need to display something on the UI, do a lot of processing and update the UI. I cannot call app.exec() before my processing, because it's a blocking function. BUT the UI is only updated once I call app.exec... It's the chiken and the egg...

    Any help?



  • I solved your issues completely in QML without anything else.
    That's my solution:

    create a splash.qml file that will be called as the main.qml with the following structure:

    @
    Item {
    // this is the item displaying your splash image
    Item {
    Image {
    ….
    }
    // for animation the stuff you have to use the Animators !!
    SequentialAnimation {
    loops: Animation.Infinite
    running: true
    RotationAnimator {

    }
    }
    } // here close the item displaying the splash screen

    // this is the Loader that's load the your 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 ) {
                                main.source = "main.qml"
                        }
                }
        }
    
    // this start the animation and loading of mail.qml when the component is ready
    Component.onCompleted: fakeLoadingDelay.start()
    

    }
    @

    The rationale is the following:

    • the Loader is asynchronous and the source is null
    • so, when the splash is loaded the only thing that are created and started are the first Item with your splash image and the animator (this has to be a very fast item to load)
    • after completed on the onCompleted a PauseAnimation is started; this because when the onCompleted is executed there is nothing on the screen yet, you need to wait some milliseconds to allow Qt to draw stuff (50ms is enough)
    • after this pause, the source of the Loader is stetted to "mail.qml" that do the heavy loading stuff
    • the result is that the first Item with the Animator will be appear very fast (less than 1 sec) and it will display an animation until your "main.qml" has finished to load itself and will stop the animation.


  • Gianluca, thanks a lot for your example and explanations! That's exactly what I needed!
    Your example is working well for my use case. I just added one think: I call the Init() function from my C++ objet juste before "main.source = "main.qml" " so that all the C++ initialization is done before the file is loaded.

    Thanks a lot for your help!


Log in to reply