QTimer::singleShot(0, object SLOT(obj_slot())) 是做什么的?

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

初学Qt,想了解Qt提供的一个example for download operation. In downloadmanager.cpp,成员函数如下:

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

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

澄清:

我是初学者,例如:

statement1;
statement2;

我习惯于看到 statement1 运行 并在继续 statement2 之前完成。但是尝试学习 Qt 并阅读给定的示例,我看到 SLOT(startNextDownload())downloadQueue.enqueue(url); 发生后被激活。我正在尝试了解 为什么 这样做。

当前问题标题的答案

QTimer::singleShot(...) 的每次调用都在调用它的线程的 事件循环中执行 **。如果从主线程调用,它将是以 app.exec().

开始的事件循环

根据 Qt-Network-Manager-Example,此函数被调用 network-manager 被 URL 填充后 single-shot 将在 queue 完全填充后进行处理。很遗憾,qt 文档对这个主题还不是很清楚,所以有关事件处理等的更多信息,请查看 here.


旧问题标题的答案

在我开始之前,计时器用于在额外的线程中进行下载。因此 GUI 保持响应。

完整的downloadNext()方法是递归的。它只会被调用一次,直到 queue 为空。 看到这个:

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;
}

在queue为空后每个方法returns至少会打印下载完成的消息。

那么为什么这样做有效? 请参阅下面的第一章。

这会在消息队列中对回调进行排队。

计时器立即结束,一条消息被发布到消息队列中。当进程下次到达主循环时,调用startNextDownload()函数。此时,URL 在队列中。

startNextDownload() 函数从调度上下文中调用,可以安全地更改 window 内容。这样,DownloadManager class 可以在多线程应用程序中使用,其中开始下载的线程可能 运行 与 Paint[=24 的处理程序并发=] 事件。通过从处理 Paint 事件的同一线程调用它,您可以确保没有处理此类事件,并且您可以安全地更新小部件。

如果之后需要重新绘制一个小部件,它会请求重新绘制,如果该小部件当前可见,OS 将发送一个 Paint 事件。

您可以先了解有关 Class QTimer 的内容,然后再根据需要获得解决方案,please have a look here for your understanding