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

问题描述 投票:0回答:2

我是学习Qt的初学者,并试图理解Qt提供的用于下载操作的example。在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::singleShot(x, y, z)
    已经被使用过。据我了解,这是一个延迟 0 毫秒激活插槽的计时器。
  • 通过查看 Qt Assistant,我无法弄清楚 singleShot 是否是一次性设置,以给定的毫秒间隔重复激活插槽,或者是否是一次性

澄清:

我是初学者,例如:

statement1;
statement2;

我习惯于看到

statement1
运行并完成,然后再继续处理
statement2
。但是尝试学习 Qt 并阅读给定的示例,我看到
SLOT(startNextDownload())
downloadQueue.enqueue(url);
发生后被激活。我试图理解为什么这有效。

c++ qt qt4
2个回答
5
投票

这会将回调放入消息队列中。

定时器立即到期,一条消息被发布到消息队列中。当进程下次到达主循环时,将调用

startNextDownload()
函数。此时,该 URL 已经在队列中了。

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

如果之后需要重新绘制某个小部件,它会要求重新绘制,并且如果该小部件当前可见,操作系统将发送一个 Paint 事件。


2
投票

回答当前问题标题

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

队列为空后,每个方法都会返回,并且至少会打印下载完成的消息。

那么为什么这会起作用?

请参阅下面的第一章。

© www.soinside.com 2019 - 2024. All rights reserved.