Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSplashScreen animation
Forum Updated to NodeBB v4.3 + New Features

QSplashScreen animation

Scheduled Pinned Locked Moved Solved General and Desktop
splashscreenanimation
13 Posts 5 Posters 7.5k Views 2 Watching
  • 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.
  • VRoninV Offline
    VRoninV Offline
    VRonin
    wrote on last edited by
    #2

    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.HilkJ 1 Reply Last reply
    2
    • VRoninV VRonin

      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

      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by
      #3

      @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


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

      1 Reply Last reply
      0
      • J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #4

        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


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

        1 Reply Last reply
        4
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #5

          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.HilkJ 1 Reply Last reply
          3
          • VRoninV 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

            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #6

            @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


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

            VRoninV 1 Reply Last reply
            0
            • J.HilkJ J.Hilk

              @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.

              VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #7

              @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
              1
              • 6thC6 Offline
                6thC6 Offline
                6thC
                wrote on last edited by
                #8

                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();
                
                mzimmersM 1 Reply Last reply
                0
                • 6thC6 6thC

                  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();
                  
                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #9

                  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.HilkJ 1 Reply Last reply
                  0
                  • mzimmersM mzimmers

                    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.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #10

                    @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


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

                    mzimmersM 1 Reply Last reply
                    0
                    • J.HilkJ J.Hilk

                      @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

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by mzimmers
                      #11

                      @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?

                      JoeCFDJ 1 Reply Last reply
                      0
                      • mzimmersM 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?

                        JoeCFDJ Offline
                        JoeCFDJ Offline
                        JoeCFD
                        wrote on last edited by JoeCFD
                        #12

                        @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.

                        mzimmersM 1 Reply Last reply
                        0
                        • JoeCFDJ 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.

                          mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by mzimmers
                          #13

                          @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
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved