QT singleShot设置循环

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT singleShot设置循环相关的知识,希望对你有一定的参考价值。

void QRfbClient::eventOperation()
...........
QTimer::singleShot(10, this, SLOT(eventOperation()));
上面一段代码的意思是不是产生一个眉0.01秒执行一次的循环呢

singleShot,表示它只会触发一次,发出一次信号,然后来执行槽函数
但是在这里,你把槽函数设置成eventOperation(),那么当定时器到达时候,就会执行这个函数,在这个函数中定时器又会再次发出信号,然后执行槽函数eventOperation,这样循环往复的
所以这是一个每隔10毫秒就执行一次的循环

不知理解没有
参考技术A 首先上面的计时器只会执行一次,如果想要每隔0.01秒触发的话可以用
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(eventOperation()));
timer->start(10);
这段代码如果设置setSingleShot(true)的话,程序也将只执行一次。

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

【中文标题】QTimer::singleShot(0, object SLOT(obj_slot())) 做啥?【英文标题】:What does QTimer::singleShot(0, object SLOT(obj_slot())) do?QTimer::singleShot(0, object SLOT(obj_slot())) 做什么? 【发布时间】:2017-01-07 17:20:17 【问题描述】:

我是初学者学习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()(注意:如果downloadQueue 为空,则startNextDownload() 结束程序) 我不确定为什么:QTimer::signleShot(x, y, z) 已经被使用了。据我了解,它是一个以 0 毫秒的延迟激活插槽的计时器。 通过查看 Qt 助手,我无法确定 singleShot 是一次性设置,以在给定的毫秒间隔内重复激活插槽,还是一次性设置

澄清:

我是初学者,例如:

statement1;
statement2;

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

【问题讨论】:

是 QT4 吗?你不是在用 QT5 吗? 我使用的是 Qt 4.8.7。 好吧,只是想知道你是 qt 的初学者。通常初学者会使用我认为的最新版本:) 感谢这个问题,讽刺的是它帮助我更好地理解了这些东西 【参考方案1】:

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

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

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

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

【讨论】:

谢谢,这有点清楚了。由于我没有进行任何线程编程,因此我将其理解为将其推送到待办事项队列中,稍后将一一完成。但是为什么 SLOT(startNextDownload() 确保在将 url 添加到 downloadQueue 之后运行(即使插槽出现/推送到添加之前要做的事情)?我也不明白:什么是主循环,是什么导致进程到达主循环?但我不知道“当进程下一次到达主循环时”是什么意思:主循环是什么,是什么导致它到达主循环? @RobertC.Holland,等等.. 你是对的,在多线程应用程序中,这可能会很糟糕。我会将其重写为bool const needToStart = downloadQueue.isEmpty(); downloadQueue.enqueue(url); if(needToStart) QTimer::singleShot(...); @RobertC.Holland,主循环是程序空闲时所在的位置。这是一个无限循环,它从队列中获取第一个事件并处理它,如果没有事件剩余,它会要求操作系统给其他进程 CPU 时间或关闭 CPU,直到发生有趣的事情。 GUI程序通常只包含一堆事件处理程序,当它们返回时,程序返回到主循环。 感谢您的解释。我现在这样解释程序(如果我错了,请纠正我):QTimer::singleShot(0, this, SLOT(startNextDownload())); 告诉在 0 毫秒内添加/推送到主循环的消息队列。所以,消息队列上的最后一件事是运行成员函数DownloadManager::append()(其中singleShot 不会跳转到调用槽,而只是调度运行之后)等等,接下来的事情将是DownloadManager::startNextDownload() after DownloadManager::append() 完全结束。谢谢! 计时器是个谎言。 “计时器立即过去”的说法是错误的。 QTimer::singleShot(0, ...) 用词不当,它所做的事情与 QTimer::singleShot 的所有其他调用完全不同。这是一个特例,意思是:“下次事件循环启动时再做”。时间无处可寻,而且 Qt 甚至使用名为“定时器”的句柄在内部实现它的事实具有误导性:那些“定时器”实际上并不使用任何平台定时器,它们只是事件循环使用的句柄。一个零持续时间的计时器在 Qt 中并不是一个计时器,尽管它的名字如此。【参考方案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;

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

那么为什么会这样呢? 请参阅下面的第一章。

【讨论】:

感谢您提供详细信息,但是QTimer::singleShot(0, this, SLOT(startNextDownload())); 作为一个单独的线程,它如何保证在downloadQueue.enqueue(url); 发生之前运行(假设它只有一个主线程)? 因为它运行在qt事件线程上,调用app.exec()后开始执行 我不确定这是否正确。 AFAIK 插槽将在 this 所属的任何线程上运行。这不一定是主 UI 线程(根据文档,该函数将在接收器的线程中运行)。因此,正如目前所说,答案是完全错误的。 您能否参考一下文档。 @ArthurP.R.:请参阅此blog.bbv.ch/2012/10/03/multithreaded-programming-with-qt 博客文章,了解当前在 Qt 中实现的线程关联性的解释。小故事 - 每个 QObject 都有线程亲和性,排队的信号连接会自动在正确的线程中保持执行【参考方案3】:

在你最终得到你想要的解决方案之前,你可以了解关于 Class QTimer 的事情,please have a look here for your understanding

【讨论】:

很抱歉,这并没有正确解决问题。

以上是关于QT singleShot设置循环的主要内容,如果未能解决你的问题,请参考以下文章

QT延时方法整理(QTimer::singleShot,QWaitCondition,QDateTime.secsTo三种新方法)

Qt中使用定时器(可使用QObject::timerEvent定时执行,QTimer::singleShot可只触发一次)

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

如何让Qt 的程序等待一段时间

qt中定时器启动后是在不断的循环定时吗 比如定义一个1s定时器 1s后它又重新开始定时吗

QTimer::singleShot()函数使用