Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does QTimer::singleShot(0, object SLOT(obj_slot())) do?

Tags:

c++

qt

qt4

I'm beginner learning Qt, and trying to understand a Qt provided example for download operation. In downloadmanager.cpp, a member function is the following:

void DownloadManager::append(const QUrl &url)
{
    if (downloadQueue.isEmpty())
        QTimer::singleShot(0, this, SLOT(startNextDownload()));

    downloadQueue.enqueue(url);
    ++totalCount;
}
  • I'm confused to why, if downloadQueue is empty, it will need to activate the startNextDownload() before adding the url. (note that: startNextDownload() ends the program if the downloadQueue is empty)
  • I'm unsure why: QTimer::signleShot(x, y, z) has been used at all. As I understand it to be, a timer that activates the slot with delay of 0 millisecond.
  • I could not figure out from looking at Qt Assistant whether singleShot is a one time setup for repeated activation to the slot at given millisecond interval or whether it is one time

Clarification:

I'm a beginner and in examples like:

statement1;
statement2;

I'm used to seeing statement1 running and finishing before moving on to working on statement2. But trying to learn Qt and reading the given example, I see the SLOT(startNextDownload()) being activated after downloadQueue.enqueue(url); has taken place. I am trying to understand why does this work.

like image 531
Robert C. Holland Avatar asked Jan 07 '17 17:01

Robert C. Holland


2 Answers

This queues a callback in the message queue.

The timer immediately elapses, and a message is posted to the message queue. When the process reaches the main loop for the next time, the startNextDownload() function is called. By this time, the URL is in the queue.

The startNextDownload() function is called from the dispatch context, where it is safe to change window contents. This way, the DownloadManager class can be used from a multithreaded application, where the thread starting the download might be running concurrently with the handler for a Paint event. By invoking it from the same thread that would handle Paint events you can be sure that no such event is being processed, and you can update widgets safely.

If a widget needs to be repainted afterwards, it then asks to be repainted, and the OS will send a Paint event if the widget is currently visible.

like image 117
Simon Richter Avatar answered Oct 19 '22 23:10

Simon Richter


Answer to current question title

Every call to QTimer::singleShot(...) is executed on the event loop of the thread where it is invoked **. If invoked from the main thread, it'll be the event loop started with app.exec().

According to the Qt-Network-Manager-Example, this function is called after the network-manager is filled with the URL's so the single-shot will be processed after the queue has been completely filled. Poorly the qt documentation isn't that clear about this topic yet, so for more information about event processing etc please look here.


Answer for old question title

Before I start, the timer is for having the download in an extra thread. So the GUI keeps responsive.

The complete downloadNext() method is recursive. It will be only called once and called till the queue is empty. See this:

void DownloadManager::append(const QStringList &urlList)
{
    foreach (QString url, urlList)
        append(QUrl::fromEncoded(url.toLocal8Bit())); //Call for only one URL
  ...
}

void DownloadManager::append(const QUrl &url)
{
    if (downloadQueue.isEmpty())
        //I'm only called if the queue is empty! And I will be called after the next line. Not instantly!
        QTimer::singleShot(0, this, SLOT(startNextDownload()));  

    downloadQueue.enqueue(url);
    ++totalCount;
}

After the queue is empty each method returns and at least the message that the download is done will be printed.

So why does this work? Please see first chapter below.

like image 31
realvictorprm Avatar answered Oct 20 '22 00:10

realvictorprm