Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved QSplashScreen animation

    General and Desktop
    splashscreen animation
    5
    13
    6000
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J.Hilk
      J.Hilk Moderators last edited by

      Hello everyone, a simple question, I believe.

      I have Q QSplashScreen for my application, to bridge loadup and show some credits, firm logo etc.

      To give it a bit of an extra flair, I derived QSplashScreen to add an animation.

      The problem, while the app is setting itself up, the SplashScreen, visible to the animation, freezes.

      Even placed in a seperate Thread I have to call QApplication::processEvents() during the Setup to see anything of my animation.
      I was surpised it compiled at all, as there is the only one MainThread my handle the UI thing.

      The problem is that ui->setupUi(this); in my classes takes a significant amount of time that results in an obvious freeze of the QSplashScreen.

      So my question is it possible to have an animated QSplashscreen without regulary calling QApplication::processEvents(); Or do I have to make it a seperated program, start is started before my main programm to have that effect?

      Code example:

      //Main
      QElapsedTimer time; time.start();
      
          QApplication::setAttribute(Qt::AA_Use96Dpi);
          QApplication a(argc, argv);
      
          QImage pMap (":/images/Logo.png");
          QPainter painter(&pMap);
          QString credits("Credits");
          QFont f = painter.font(); f.setPixelSize(16); painter.setFont(f);
          QFontMetrics fMetric (painter.font());
          QRect rec = fMetric.boundingRect(credits);
          painter.drawText((pMap.width()-rec.width())/2,(pMap.height()-rec.height()*1),credits);
      
          jhSplashScreen *splash = new jhSplashScreen();
          splash->setImage(pMap);
      
          splash->setWindowFlags( Qt::WindowStaysOnTopHint | Qt::SplashScreen | Qt::FramelessWindowHint );
      
          splash->show();
      
          QThread *t = new QThread();
          splash->moveToThread(t);
          QObject::connect(t, &QThread::started, splash, &jhSplashScreen::init);
          QObject::connect(t, &QThread::finished, splash, &jhSplashScreen::deleteLater);
          QObject::connect(t, &QThread::finished, t,      &QThread::deleteLater);
          t->start();
      
          myApp w;
      
          if(!w.lock())
              return -42;
      
          while(time.elapsed() < 5450){
              QApplication::processEvents();
          }
      
          w.show();
          t->quit();
      
          return a.exec();
      

      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

      Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      1 Reply Last reply Reply Quote 0
      • J.Hilk
        J.Hilk Moderators last edited by

        So, I think I found a solution that works.
        I'm not sure however, if it is the most elegant solution.

        I turned the SplshScreen animation into its own program, compiled that as an executable:

        The Splash.exe and my main program have each a QSharedMemory object.
        The QSharedMemory is aparently also freed, when I kill my main program via TaskManager.

        After 5 seconds, I check from my splash app if the Object was created/is maintained from my main program. If it isn't -> cancel program else wait for cancle from main program.

        jhSplash::jhSplash(QWidget *parent) : QWidget(parent)
        {
            _MainApp = new QSharedMemory("myAppSingleInstance",this);
            this->setWindowFlags( Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowTransparentForInput);
            this->setAttribute(Qt::WA_TranslucentBackground,true);
            
            m_Img = QImage(":/Logo.png");
            
            this->resize(m_Img.size());
            
            m_updateTimer = new QTimer(this);
            connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(repaint()));
            m_updateTimer->start(6);
        
            this->show();
            QTimer::singleShot(5000,this,[=]{m_CheckMemory = true;});
        }
        
        jhSplash::~jhSplash()
        {
        
        }
        
        void jhSplash::paintEvent(QPaintEvent *event)
        {
            int penWidth = 6;
            QRectF oRect (0,0,this->width(), this->height());
            QPainter painter(this);
            painter.setBackgroundMode(Qt::TransparentMode);
            painter.drawImage(0,0,m_Img);
            QString credits("Credits");
            QFont f = painter.font(); f.setPixelSize(16); painter.setFont(f);
            QFontMetrics fMetric (painter.font());
            QRect rec = fMetric.boundingRect(credits);
            painter.drawText((oRect.width()-rec.width())/2,(oRect.height()-rec.height()*1),credits);
        
            QPen pen;
            pen.setWidth(penWidth);
            pen.setColor(Qt::black);
            painter.setPen(pen);
        
            QRect arcRect(penWidth/2,penWidth/2,this->width()-penWidth,this->height()-penWidth);
        
            m_drawAngle = m_drawAngle +16;
            int startAngle = 0+m_drawAngle;
            int spanAngle = (5760 -960)*(-1);
            painter.drawArc(arcRect,startAngle,spanAngle);
        
            pen.setColor(Qt::red);
            painter.setPen(pen);
            startAngle = 0 + m_drawAngle;
            spanAngle  = 960;
            painter.drawArc(arcRect,startAngle,spanAngle);
        
            if(m_CheckMemory){
                if(!_MainApp->attach(QSharedMemory::ReadOnly)){
                    this->close();
                }
                _MainApp->detach();
            }
        
            QWidget::paintEvent(event);
        }
        
        //Main Application main.cpp
        
        QElapsedTimer time; time.start();
        
            QApplication::setAttribute(Qt::AA_Use96Dpi);
            QApplication a(argc, argv);
        
            QProcess splash;
            splash.start("path/to/Splash/Splash.exe");
        
            uConfig w;
        
            if(!w.lock())
                return -42;
        
            while(time.elapsed() < 5450){
            }
        
            w.show();
            splash.close();
        
            QObject::connect(&a, &QApplication::aboutToQuit, &splash, &QProcess::close);
        
            return a.exec();
        

        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

        Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply Reply Quote 4
        • VRonin
          VRonin last edited by

          this

          while(time.elapsed() < 5450){
                  QApplication::processEvents();
              }
          

          is useless.

          GUI operations are only allowed in the same thread the QApplication lives so the multi-thread is not feasible.

          I'd say the fastest way here is to move the splash to a separate binary altogether and use QProcess to control it

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          J.Hilk 1 Reply Last reply Reply Quote 2
          • J.Hilk
            J.Hilk Moderators @VRonin last edited by

            @VRonin said in QSplashScreen animation:

            this

            while(time.elapsed() < 5450){
                    QApplication::processEvents();
                }
            

            is useless.

            Actually, not entirely useless, this garanties at least 5 seconds of splashscreen. And processEvents was so only way I managed to update the animation.

            GUI operations are only allowed in the same thread the QApplication lives so the multi-thread is not feasible.

            I'd say the fastest way here is to move the splash to a separate binary altogether and use QProcess to control it

            That was what I suspected. The question I have to that, is there a way to also close the seperated Process if the user terminated the app in an unusual way, e.g. forces a close via taskmanager?

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

            Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            1 Reply Last reply Reply Quote 0
            • J.Hilk
              J.Hilk Moderators last edited by

              So, I think I found a solution that works.
              I'm not sure however, if it is the most elegant solution.

              I turned the SplshScreen animation into its own program, compiled that as an executable:

              The Splash.exe and my main program have each a QSharedMemory object.
              The QSharedMemory is aparently also freed, when I kill my main program via TaskManager.

              After 5 seconds, I check from my splash app if the Object was created/is maintained from my main program. If it isn't -> cancel program else wait for cancle from main program.

              jhSplash::jhSplash(QWidget *parent) : QWidget(parent)
              {
                  _MainApp = new QSharedMemory("myAppSingleInstance",this);
                  this->setWindowFlags( Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowTransparentForInput);
                  this->setAttribute(Qt::WA_TranslucentBackground,true);
                  
                  m_Img = QImage(":/Logo.png");
                  
                  this->resize(m_Img.size());
                  
                  m_updateTimer = new QTimer(this);
                  connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(repaint()));
                  m_updateTimer->start(6);
              
                  this->show();
                  QTimer::singleShot(5000,this,[=]{m_CheckMemory = true;});
              }
              
              jhSplash::~jhSplash()
              {
              
              }
              
              void jhSplash::paintEvent(QPaintEvent *event)
              {
                  int penWidth = 6;
                  QRectF oRect (0,0,this->width(), this->height());
                  QPainter painter(this);
                  painter.setBackgroundMode(Qt::TransparentMode);
                  painter.drawImage(0,0,m_Img);
                  QString credits("Credits");
                  QFont f = painter.font(); f.setPixelSize(16); painter.setFont(f);
                  QFontMetrics fMetric (painter.font());
                  QRect rec = fMetric.boundingRect(credits);
                  painter.drawText((oRect.width()-rec.width())/2,(oRect.height()-rec.height()*1),credits);
              
                  QPen pen;
                  pen.setWidth(penWidth);
                  pen.setColor(Qt::black);
                  painter.setPen(pen);
              
                  QRect arcRect(penWidth/2,penWidth/2,this->width()-penWidth,this->height()-penWidth);
              
                  m_drawAngle = m_drawAngle +16;
                  int startAngle = 0+m_drawAngle;
                  int spanAngle = (5760 -960)*(-1);
                  painter.drawArc(arcRect,startAngle,spanAngle);
              
                  pen.setColor(Qt::red);
                  painter.setPen(pen);
                  startAngle = 0 + m_drawAngle;
                  spanAngle  = 960;
                  painter.drawArc(arcRect,startAngle,spanAngle);
              
                  if(m_CheckMemory){
                      if(!_MainApp->attach(QSharedMemory::ReadOnly)){
                          this->close();
                      }
                      _MainApp->detach();
                  }
              
                  QWidget::paintEvent(event);
              }
              
              //Main Application main.cpp
              
              QElapsedTimer time; time.start();
              
                  QApplication::setAttribute(Qt::AA_Use96Dpi);
                  QApplication a(argc, argv);
              
                  QProcess splash;
                  splash.start("path/to/Splash/Splash.exe");
              
                  uConfig w;
              
                  if(!w.lock())
                      return -42;
              
                  while(time.elapsed() < 5450){
                  }
              
                  w.show();
                  splash.close();
              
                  QObject::connect(&a, &QApplication::aboutToQuit, &splash, &QProcess::close);
              
                  return a.exec();
              

              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

              Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              1 Reply Last reply Reply Quote 4
              • VRonin
                VRonin last edited by VRonin

                While I like your solution best, below an alternative based on a heartbeat socket:

                Splash App

                splashwidget.h

                #ifndef SPLASHWIDGET_H
                #define SPLASHWIDGET_H
                
                #include <QWidget>
                #include <QTimer>
                #include <QLocalSocket>
                #include <QApplication>
                #include <QDataStream>
                class SplashWidget : public QWidget
                {
                    Q_OBJECT
                    Q_DISABLE_COPY(SplashWidget)
                    enum {ContinueChar = 88};
                public:
                    SplashWidget(const QString& serverName, QWidget* parent= Q_NULLPTR)
                        :QWidget(parent)
                        ,m_serverName(serverName)
                    {
                        init();
                    }
                    virtual ~SplashWidget() {}
                protected:
                    void init(){
                        setWindowFlags( Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowTransparentForInput);
                        setAttribute(Qt::WA_TranslucentBackground,true);
                        m_hbTimer = new QTimer(this);
                        connect(m_hbTimer,&QTimer::timeout,this,&SplashWidget::resetTimer);
                        m_hbTimer->setInterval(1000); // 1 sec
                        m_hbReceiver = new QLocalSocket(this);
                        connect(m_hbReceiver, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error),qApp,&QApplication::quit);
                        connect(m_hbReceiver, &QLocalSocket::disconnected,qApp,&QApplication::quit);
                        connect(m_hbReceiver, &QLocalSocket::readyRead, this, &SplashWidget::resetTimer);
                        connect(m_hbReceiver, &QLocalSocket::connected, m_hbTimer, static_cast<void(QTimer::*)()>(&QTimer::start));
                        m_hbReceiver->connectToServer(m_serverName,QIODevice::ReadOnly);
                    }
                    Q_SLOT void resetTimer(){
                        if(m_hbReceiver->bytesAvailable()>=sizeof(qint8)){
                            QDataStream hbin(m_hbReceiver);
                            hbin.setVersion(QDataStream::Qt_5_0);
                            qint8 readHb=0;
                            hbin >> readHb;
                            if(readHb == static_cast<qint8>(ContinueChar))
                                return m_hbTimer->start();
                            qApp->quit();
                        }
                    }
                private:
                    const QString m_serverName;
                    QTimer* m_hbTimer;
                    QLocalSocket* m_hbReceiver;
                
                };
                #endif
                

                main.cpp

                #include "splashwidget.h"
                #include <QApplication>
                
                int main(int argc, char *argv[])
                {
                    QApplication a(argc, argv);
                    const QStringList argList = a.arguments();
                    if(argList.size()<2)
                        return -1;
                    if(argList.at(1).isEmpty())
                        return -1;
                    SplashWidget w(argList.at(1));
                    w.show();
                
                    return a.exec();
                }
                

                Main Application

                splashcontroller.h

                #ifndef SPLASHCONTROLLER_H
                #define SPLASHCONTROLLER_H
                #include <QObject>
                #include <QUuid>
                #include <QLocalServer>
                #include <QLocalSocket>
                #include <QTimer>
                #include <QProcess>
                #include <QDataStream>
                class SplashController : public QObject
                {
                    Q_OBJECT
                        Q_DISABLE_COPY(SplashController)
                public:
                    SplashController(QObject* parent = Q_NULLPTR)
                        :QObject(parent)
                        , m_localSocket(Q_NULLPTR)
                        , m_localServer(Q_NULLPTR)
                        , m_splashProcess(Q_NULLPTR)
                        , m_splashProcessPath("SplashScreenApp")
                    {
                        m_hbTimer = new QTimer(this);
                        m_hbTimer->setInterval(500);
                    }
                    QString splashProcessPath() const
                    {
                        return m_splashProcessPath;
                    }
                
                    void setSplashProcessPath(const QString &splashProcessPath)
                    {
                        m_splashProcessPath = splashProcessPath;
                    }
                    Q_SLOT void start()
                    {
                        if (m_localServer)
                            return;
                        const QString serverName = QUuid::createUuid().toString();
                        m_localSocket = Q_NULLPTR;
                        m_localServer = new QLocalServer(this);
                        if (!m_localServer->listen(serverName)) {
                            m_localServer->deleteLater();
                            m_localServer = Q_NULLPTR;
                            error();
                        }
                        QObject::connect(m_localServer, &QLocalServer::newConnection, this, &SplashController::splashConnected);
                        m_splashProcess = new QProcess(this);
                        QObject::connect(m_splashProcess, &QProcess::errorOccurred, this, &SplashController::stopComponents);
                        QObject::connect(m_splashProcess, &QProcess::errorOccurred, this, &SplashController::error);
                        QObject::connect(m_splashProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &SplashController::stopComponents);
                        QObject::connect(m_splashProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &SplashController::error);
                        m_splashProcess->start(m_splashProcessPath, QStringList(serverName));
                
                    }
                    Q_SLOT void stop()
                    {
                        stopComponents();
                        finished();
                    }
                    Q_SIGNAL void error();
                    Q_SIGNAL void finished();
                protected:
                    Q_SLOT void stopComponents()
                    {
                        if (!m_localServer)
                            return;
                        m_hbTimer->stop();
                        disconnect(m_splashProcess);
                        disconnect(m_localServer);
                        if (m_localSocket)
                            disconnect(m_localSocket);
                        m_splashProcess->deleteLater();
                        m_localServer->deleteLater();
                        m_splashProcess = Q_NULLPTR;
                        m_localServer = Q_NULLPTR;
                        m_localSocket = Q_NULLPTR;
                    }
                
                    Q_SLOT void splashConnected()
                    {
                        if (m_localSocket)
                            return;
                        m_localSocket = m_localServer->nextPendingConnection();
                        QObject::connect(m_localSocket, &QLocalSocket::disconnected, this, &SplashController::stopComponents);
                        QObject::connect(m_localSocket, &QLocalSocket::disconnected, this, &SplashController::error);
                        QObject::connect(m_localSocket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), this, &SplashController::stopComponents);
                        QObject::connect(m_localSocket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), this, &SplashController::error);
                        QObject::connect(m_hbTimer, &QTimer::timeout, this, &SplashController::spalshHB);
                        m_hbTimer->start();
                    }
                    Q_SLOT void spalshHB()
                    {
                        if (!m_localSocket)
                            return;
                        QDataStream hbin(m_localSocket);
                        hbin.setVersion(QDataStream::Qt_5_0);
                        hbin << static_cast<qint8>(88);
                    }
                
                private:
                    QTimer* m_hbTimer;
                    QLocalServer* m_localServer;
                    QLocalSocket* m_localSocket;
                    QProcess* m_splashProcess;
                    QString m_splashProcessPath;
                };
                
                #endif // SPLASHCONTROLLER_H
                

                an example of main.cpp

                #include <QApplication>
                #include <QThread>
                #include "splashcontroller.h"
                
                int main(int argc, char *argv[])
                {
                
                    QApplication app(argc, argv);
                    QThread splashThread;
                    SplashController* splashScreen = new SplashController;
                    splashScreen->setSplashProcessPath("C:/temp/SplashScreenApp");
                    splashScreen->moveToThread(&splashThread);
                    QObject::connect(splashScreen, &SplashController::finished, &splashThread, &QThread::quit);
                    QObject::connect(splashScreen, &SplashController::error, &splashThread, &QThread::quit);
                    QObject::connect(splashScreen, &SplashController::finished, splashScreen, &SplashController::deleteLater);
                    QObject::connect(splashScreen, &SplashController::error, splashScreen, &SplashController::deleteLater);
                    QObject::connect(splashScreen, &SplashController::finished, [&splashScreen]()->void {splashScreen = Q_NULLPTR; });
                    QObject::connect(splashScreen, &SplashController::error, [&splashScreen]()->void {splashScreen = Q_NULLPTR; });
                    QObject::connect(&splashThread, &QThread::started, splashScreen, &SplashController::start);
                    splashThread.start();
                    QTimer::singleShot(10000, [&splashScreen]()->void {
                        QMetaObject::invokeMethod(splashScreen, "stop", Qt::QueuedConnection);
                    });
                    QTimer::singleShot(10100, &app, &QApplication::quit);
                    return app.exec();
                }
                

                Of course you'll have to subclass SplashWidget and implement your own paint

                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                ~Napoleon Bonaparte

                On a crusade to banish setIndexWidget() from the holy land of Qt

                J.Hilk 1 Reply Last reply Reply Quote 3
                • J.Hilk
                  J.Hilk Moderators @VRonin last edited by

                  @VRonin Thanks for the detailed and complex answer! I'll defenitly look into your heartbeat approach a bit more!

                  I wanted to add a few lines, of code that I forgot in my post above.

                  The QShared Memory part of the main-app main.cpp:

                   QApplication::setAttribute(Qt::AA_Use96Dpi);
                      QApplication a(argc, argv);
                  //!New Part start
                  QSharedMemory _singular("myAppSingleInstance");
                      if(_singular.attach(QSharedMemory::ReadOnly)){
                          _singular.detach();
                          return -42;
                      }else{
                          _singular.create(1);
                      }
                  //!New Part End
                      QProcess 
                  

                  And also a small addition, so that noone accidentally starts Splash.exe without a main App:

                  //Main Application, main.cpp
                  QProcess splash;
                  QStringList s{"openByApp"};
                  splash.start("path/to/Splash/Splash.exe",s);
                  
                  //Splash App, main.cpp
                  QApplication a(argc, argv);
                      if(a.arguments().last() != "openByApp"){
                          return -42;
                      }
                  

                  Also on a second thought, this would also be the perfect situtation to test Qt 5.9's brand new Technology Preview Module : Qt Remote Objects ?

                  It seems to fit, according to the quick description I read.

                  Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

                  Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


                  Q: What's that?
                  A: It's blue light.
                  Q: What does it do?
                  A: It turns blue.

                  VRonin 1 Reply Last reply Reply Quote 0
                  • VRonin
                    VRonin @J.Hilk last edited by VRonin

                    @J.Hilk said in QSplashScreen animation:

                    Also on a second thought, this would also be the perfect situtation to test Qt 5.9's brand new Technology Preview Module : Qt Remote Objects ?

                    My solution uses the principles behind this. It uses the "local" connection and, given the simplicity of the inter-process communication in this case, You probably do not need the overhead of that module. QSharedMemory is perfect in this case even though your current code probably doesn't handle opening the main app twice well

                    A side note for curious readers:
                    You might ask why we are using QSharedMemory or QLocalSocket instead of using stdin/stdout to communicate between processes and the answer is that on Windows stdin is not a socket so you can't use QSocketNotifier to get a sort of readyRead() in the child process. In this specific case you probably can have a thread in the child just stuck on a std::cin call until the server responds, but I'm not going to try it

                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                    ~Napoleon Bonaparte

                    On a crusade to banish setIndexWidget() from the holy land of Qt

                    1 Reply Last reply Reply Quote 1
                    • 6thC
                      6thC last edited by

                      Not sure this will help. But I only wished to have messages animate for my splash. And this is what I do:

                      In my main I define a QApplication derived class:

                      MyAppObject app(argc, argv);
                      

                      I construct the object, I have an init method that emits progress signal messages such as:

                      message="Reading configurations: " % settings.fileName();
                      emit initMessage(message);
                      

                      Back in main, after app is declared but before app.init():

                          const QImage image(":/Images/Splash.png");
                          QPixmap pixmap = QPixmap::fromImage(image).scaled(QSize(300,300)
                                             ,Qt::AspectRatioMode::KeepAspectRatio
                                             ,Qt::SmoothTransformation);
                          QSplashScreen *splash = new QSplashScreen(pixmap);
                          splash->show();
                      // bind app init messsage signals/updates to splash message
                      QObject::connect(&app, &ClassName::initMessage,
                          [=]( const QString message){
                              int alignment = Qt::AlignCenter;
                              const QColor &color = Qt::darkYellow;
                              splash->showMessage(message, alignment, color);
                              } 
                      // start the fun
                      app.Init();
                      // everything is ready, kill off the splash
                      splash->close();
                      // start the QApp
                      return app.exec();
                      
                      mzimmers 1 Reply Last reply Reply Quote 0
                      • mzimmers
                        mzimmers @6thC last edited by

                        Hi guys - I'm going to pull this topic out of mothballs, just to ask...in the intervening years, has there been any developments that would make this task more straightforward? The customer wants an animated splash screen...will have to work on Android as well as desktops.

                        Thanks...

                        J.Hilk 1 Reply Last reply Reply Quote 0
                        • J.Hilk
                          J.Hilk Moderators @mzimmers last edited by

                          @mzimmers hi, as far as I know, there is no easier way in Qt than the QProcess one. Due to the nature of Qt and all GUI Stuff in one thread concept. Any long, consecutive, GUI Creation will cause freezes of the animation.

                          -> Standalone SplashScreen executable launched via QProcess.

                          Android is even more complicated. Because you actually have 2 different phases, the launch, which is purely OS handled and then the initialisation of your app where you can influence stuff.

                          You may have noticed when starting a bare bone application on android, it starts with a black screen transitioning into a white one with your application name written on it.

                          You where always able to replace the black screen with a static splash screen of your choice and only with android 12 they added the possibility to make this animated:
                          https://developer.android.com/develop/ui/views/launch/splash-screen

                          IIRC the white one you could make animated in the past

                          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

                          Qt Needs YOUR vote: https://bugreports.qt.io/browse/QTQAINFRA-4121


                          Q: What's that?
                          A: It's blue light.
                          Q: What does it do?
                          A: It turns blue.

                          mzimmers 1 Reply Last reply Reply Quote 0
                          • mzimmers
                            mzimmers @J.Hilk last edited by mzimmers

                            @J-Hilk it occurs to me that there's more than one purpose for a splash screen:

                            1. it displays some desired information for a minimum period of time
                            2. it gives the user something to look at while the app is loading

                            What this would be (in non-technical terms) is: the app starts by playing a movie, while all the behind-the-scenes stuff is doing whatever it does. After some pre-set period of time, the movie player will accept a signal to end. This signal would come from the worker. The worker would then take over the display.

                            The difficulty here, IMO, is to get the movie player and the rest of the app to share one window. I'm not sure how I'd go about that.

                            I haven't built for Android in a few months, but as I remember, Qt Creator provides the hooks to install an animated splash screen for Android, no?

                            JoeCFD 1 Reply Last reply Reply Quote 0
                            • JoeCFD
                              JoeCFD @mzimmers last edited by JoeCFD

                              @mzimmers I did it with two loaders inside qml ApplicationWindow on Android. The splash screen part is an animated widget and stopped by a timer.

                              mzimmers 1 Reply Last reply Reply Quote 0
                              • mzimmers
                                mzimmers @JoeCFD last edited by mzimmers

                                @JoeCFD yeah, that's what I had in mind (I think). What QML class did you use for your animated widget? (EDIT: I imagine it's AnimatedImage.) And, does yours have a minimum play time before it can be interrupted?

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post