5

I want to update my QMainWindow step by step. I use sleep method but I cannot see changes. I want to see changes every 3 seconds.

void MainWindow::updateScreen()
{
    ui->pushButton1->show();
    QThread::sleep(3);

    ui->pushButton2->show();
    QThread::sleep(3);

    ui->pushButton3->show();
    QThread::sleep(3);
}

But after 9 seconds, all changes apply immediately.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
sepfar
  • 53
  • 2

3 Answers3

6

You never use QThread::sleep() in the main thread because it prevents the GUI from being notified about the events and consequently does not behave correctly, the other questions argue correctly so I will not dedicate myself to it, my answer will be centered in giving you a solution that I think is the most appropriate with the use of QTimeLine:

const QWidgetList buttons{ui->pushButton1, ui->pushButton2, ui->pushButton3};

QTimeLine *timeLine =  new QTimeLine( 3000*buttons.size(), this);
timeLine->setFrameRange(0, buttons.size());
connect(timeLine, &QTimeLine::frameChanged, [buttons](int i){
    buttons[i-1]->show();
});
connect(timeLine, &QTimeLine::finished, timeLine, &QTimeLine::deleteLater);
timeLine->start();

I do not recommend using processEvents() because many beginners abuse it thinking it is the magic solution, for example the @cbuchart solution is incorrect because it solves the immediate problem but not the background, for example try to change the size of the window in those 9 seconds. Can you do it? Well, not since the QThread::sleep() is blocking.

Consider a bad practice to use QThread::sleep() in the GUI thread, if you see it somewhere, mistrust.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
5

I would suggest you to use QTimer::singleShot static method.

void MainWindow::updateScreen()
{
    QTimer::singleShot(3000, [this](){ui->pushButton1->show();});
    QTimer::singleShot(6000, [this](){ui->pushButton2->show();});
    QTimer::singleShot(9000, [this](){ui->pushButton3->show();});
}
Andrii
  • 1,788
  • 11
  • 20
1

Applied changes do not become visible until the window is actually drawn. By sleeping on the main UI thread, you prevent the system from doing any drawing at all, so you cannot see the updates happening until you leave the update function again after 9 seconds.

What you would want to do instead is have a separate thread that is not blocking the main UI thread emit signals every three seconds that cause the individual buttons to appear. Be sure you put those signals on a QueuedConnection to avoid race conditions on the widgets.

Alternatively, if you don't want to waste a thread, you can also have a continuous update event that checks how much time has elapsed since the beginning of the current update cycle and show the respective buttons only after enough time has passed. The QTimer class provides a convenient way of doing this. Just be sure that you don't block the event loop by performing heavy computations or sleeping on the same thread, or you will again not be able to see the updates.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166