我是初学者学习Qt,并尝试了解提供example的Qt进行下载操作。在downloadmanager.cpp中,成员函数如下:
void DownloadManager::append(const QUrl &url)
{
if (downloadQueue.isEmpty())
QTimer::singleShot(0, this, SLOT(startNextDownload()));
downloadQueue.enqueue(url);
++totalCount;
}
downloadQueue
为空,则需要在添加网址之前激活startNextDownload()
。 (请注意:如果startNextDownload()
为空,downloadQueue
会结束该计划 QTimer::signleShot(x, y, z)
已被使用过。据我所知,一个定时器以0毫秒的延迟激活插槽。 我是初学者,例如:
statement1;
statement2;
我常常看到statement1
正在运行和完成,然后继续工作statement2
。但是,尝试学习Qt并阅读给定的示例,我看到SLOT(startNextDownload())
在downloadQueue.enqueue(url);
发生后被激活。我试图理解为什么这样做。
答案 0 :(得分:2)
这会在消息队列中对回调进行排队。
计时器立即过去,并将消息发布到消息队列中。当进程下次到达主循环时,将调用startNextDownload()
函数。到这时,URL就在队列中。
从调度上下文调用startNextDownload()
函数,可以安全地更改窗口内容。这样,DownloadManager
类可以在多线程应用程序中使用,其中开始下载的线程可能与 Paint 事件的处理程序同时运行。通过从处理 Paint 事件的同一线程调用它,您可以确保没有处理此类事件,并且可以安全地更新窗口小部件。
如果之后需要重新绘制窗口小部件,则会要求重新绘制,如果窗口小部件当前可见,操作系统将发送 Paint 事件。
答案 1 :(得分:0)
对QTimer::singleShot(...)
的每次调用都在调用它的线程的事件循环上执行 **。如果从主线程调用,它将是以app.exec()
开头的事件循环。
根据Qt-Network-Manager-Example,在网络管理器填充了URL后,此函数被称为,因此在队列完全填满后将处理单击。 qt文档还不是很清楚这个主题,所以有关事件处理等的更多信息,请查看here。
在开始之前,计时器用于在额外的线程中进行下载。因此,GUI保持响应。
完整的downloadNext()
方法是递归的。它只会被调用一次并被调用,直到队列为空。
见:
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;
}
队列为空后,每个方法都会返回,并且至少会打印下载完成的消息。
那为什么会这样呢? 请参阅下面的第一章。
答案 2 :(得分:0)
在您根据需要找到解决方案之前,您可以了解有关QTimer课程的信息,please have a look here for your understanding