[SOLVED] QSplashScreen doesn't show unless I run QApplication::processEvents() 1000 times !?



  • In my application I have a lot of data loading when it starts, so I want to have a splash screen that says what's loading. The issue I'm having is when I show the splash screen it doesn't show. This is the code I was using originally:
    @
    QPixmap pixmap(config->getSplashPath());
    splash_screen = new SplashScreen(pixmap);
    splash_screen->show();
    QApplication::processEvents();
    @

    And this is the only way I can get it to show:
    @
    QPixmap pixmap(config->getSplashPath());
    splash_screen = new SplashScreen(pixmap);
    splash_screen->show();
    for(int i = 1; i <= 1000; i++) QApplication::processEvents();
    @

    Later I use this:
    @
    splash_screen->showMessage("Some text I want to show");
    QApplication::processEvents();
    @

    If I don't have the processEvents() run 1000 times then the splash screen only shows for a second AFTER everything has already be finished. I know I can put my "initialization" code in a second thread, but from what I've been reading I shouldn't need to, the QSplashScreen examples themselves show only using processEvents(), so what's the best way to handle this?


  • Lifetime Qt Champion

    Hi,

    Since your splash screen is a custom class, are you doing anything unusual in it ?



  • No, right now my SplashScreen class is very empty, it's essentially as if I'm directly using QSplashScreen, the only reason I created a class is so I can play with it once I get it working properly.


  • Lifetime Qt Champion

    When are you creating this splash screen ? In your main function ?
    Can you show the code where you use it ?



  • No, it's created in the constructor of my QMainWindow.
    I'll post some of my code, sorry about the syntax, I just copied and pasted, my editor is set to about 100 columns.

    Here's the constructor:
    @
    MainWindow::MainWindow() {
    // Initialize config singleton
    Config::init();

    setWindowIcon(QIcon(config->getIconPath()));

    // If config is empty, launch first run dialog
    if(config->isEmpty()) {
    int result = FirstRunDialog::run(this);

    // If FirstRunDialog was cancelled then free memory and quit app
    if(!result) {
    Config::destroy();
    // This 'exiting' status needs to be passed back to main() function and then 'return 0'
    // Using exit(0) here sometimes results in strange segfault with no real stack trace o_O
    exiting = true;
    return;
    }
    }

    // Initialize splash screen
    SplashScreen::start();

    // Initialize global actions
    eComics::Actions::init(this);

    // Initialize library right after Config and Actions are finished, but before everything else
    Library::init();

    // Initialize child widgets
    status_bar = statusBar();
    main_splitter = new QSplitter(this);
    MainSidePane::init(main_splitter);
    MainView::init(main_splitter); // Must be initialized after MainSidePane
    MenuBar::init(this);
    main_side_pane->initSelectedList(); // Must happen after MainView is initialized

    // Add widgets to window
    setCentralWidget(main_splitter);
    main_splitter->addWidget(main_side_pane);
    main_splitter->addWidget(main_view);
    main_splitter->setSizes( {150, 650} );
    main_splitter->setCollapsible(1, false);

    resize(800, 600);

    // Initialize comic info dialog
    ComicInfoDialog::init(this);

    // Initialize preferences dialog
    PreferencesDialog::init(this);

    // Connect signals to actions
    connect(eComics::actions->statusBar(), SIGNAL(toggled(bool)), this,
    SLOT(toggleStatusBar(bool)));
    connect(eComics::actions->quit(), SIGNAL(triggered()), qApp, SLOT(quit()));
    connect(eComics::actions->fullScreen(), SIGNAL(toggled(bool)), this,
    SLOT(toggleFullscreen(bool)));

    SplashScreen::finish();
    }
    @

    And here's the implementation of my SplashScreen (it's a singleton):
    @
    #include "SplashScreen.hpp"

    #include <QApplication>

    #include "Config.hpp"
    #include "MainWindow.hpp"

    SplashScreen *splash_screen = nullptr;

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    •    SPLASHSCREEN PUBLIC METHODS          *
      
                                                                                                  • */

    //THIS IS A STATIC METHOD
    void SplashScreen::start() {
    if(splash_screen == nullptr) {
    //THIS PRINTS RIGHT AWAY NO PROBLEM
    qDebug() << config->getSplashPath();
    QPixmap pixmap(config->getSplashPath());
    splash_screen = new SplashScreen(pixmap);
    splash_screen->show();
    /for(int i = 1; i <= 1000; i++)/ QApplication::processEvents();
    }
    }

    //THIS IS ALSO STATIC
    void SplashScreen::finish() {
    splash_screen->QSplashScreen::finish(main_window);
    delete splash_screen;
    splash_screen = nullptr;
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    •    SPLASHSCREEN PRIVATE METHODS          *
      
                                                                                                  • */

    SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) : QSplashScreen(pixmap, f) {
    // Don't allow clicking on splash screen to close it
    setEnabled(false);
    }

    SplashScreen::SplashScreen(QWidget *parent, const QPixmap &pixmap, Qt::WindowFlags f) :
    QSplashScreen(parent, pixmap, f) {
    setEnabled(false);
    }

    SplashScreen::~SplashScreen() {}
    @



  • Also, I tried putting it in my main.cpp, but it didn't make a difference.



  • Well I figured out the only thing that seems to work, I just have to put all my initialization work in a worker QThread, I was hoping to avoid that using processEvents(), but that doesn't look like it's going to happen.


  • Lifetime Qt Champion

    Does it also happen if you use the same code without any modification as the example provided in the documentation ?

    By the way, what are you doing in your initialization ? Anything involving the event loop ?



  • The initialization code is loading the library from XML, and it scans user selected directories for new content, it is fairly intensive (if they have a lot of content), but there is nothing GUI related (I double checked in case I forgot about something).



  • There is use of signals and slots in the initialization, that is separate from the event loop right?



  • I should also note that I don't even run app.exec() until after the initialization and the splash screen disappears.


  • Lifetime Qt Champion

    Ok, then it's clearer now. The event loop is mandatory for signals and slots to work. That's why it's working if you use a secondary thread: QThread starts it's own event loop.

    Anyway, following your description, it sounds that using a secondary thread would be best. QFileSystemModel uses one to populate its data and a signal to let the developer know it's ready to be used.



  • OK, awesome, thanks for the info! :D


  • Lifetime Qt Champion

    You're welcome !

    If that answers your question then please update the thread title prepending [solved] so other forum users may know a solution has been found :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.