手动重启计时器后,奇怪的未记录的QTimer / QEventLoop行为

时间:2014-11-13 14:54:11

标签: qt qtimer qeventloop

我最近在使用QTimer调用具有内部QEventLoop的函数时偶然发现了这个

所以,假设我们有一个QTimer实例

QTimer* timer = new QTimer;

在构造函数的某个地方,我们启动它,它开始每100毫秒滴答一次

timer->start(100);

现在是有趣的部分,我们将它连接到具有内部QEventLoop

的插槽
void SlotFunction()
{
    qDebug() << "entered";
    QEventLoop loop;
    loop.exec();
}

撇开这个循环真的是多么愚蠢,我们看到我们永远不会完成处理插槽和计时器的后续超时将继续堆叠到执行队列中。一切都很好,应该如此。

接下来应该是什么不是:因为QEventLoop确保我们的应用程序保持响应,而插槽无意识地闲置,我们可以创建一个按钮及其单击的()插槽,如下所示:

void OnClicked()
{
    timer->start(100);
}

我在这里做的事实上是重新启动当前的计时器周期,仅此而已,仅此而已。对?不!重新启动后,SlotFunction再次触发 ,提示计时器重启后的勾号实际上并不等于之前发出的所有其他滴答......

我唯一的问题是: WTF?!为什么手动重启定时器会让它进入插槽的额外时间?我问freenode,但我得到的唯一答案是&#34;它应该是&#34;

1 个答案:

答案 0 :(得分:3)

我尝试了这一点,每次点击都会创建另一个&#34;输入&#34;线。

主要的Eventloop无法处理另一个事件,因为我们陷入了新的事件循环。

在实现第二个插槽并将此插槽连接到超时信号时,很容易看到。

  • 当调用下一个eventloop并且不处理任何更多排队事件时,maineventloop将会卡住。
  • 计时器本身也不再排队任何事件,因为排队本身将在现在卡住的主事件循环中完成。计时器不会在自己的eventloop中运行(这就是为什么Qtimers不是精确定时器)。
  • 单击该按钮后,如果应生成事件timeout(),则新的eventloop将检查计时器。
  • 一旦新事件被处理,我们再次陷入另一个事件循环......
  • 这将一直持续到我们退出申请。
  • 当退出应用程序时,我们看到循环反转并且在我们点击按钮并进入第一个插槽时经常调用第二个插槽

代码:

#include <QDebug>
#include <QTime>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    timer = new QTimer;
    timer->setInterval(2000);
    connect(timer,SIGNAL(timeout()),this,SLOT(timerslot()));
    connect(timer,SIGNAL(timeout()),this,SLOT(timerslot2()));
    timer->start();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    timer->start(2000);
}

void MainWindow::timerslot()
{
    qDebug()<<"In";
    QEventLoop loop;
    loop.exec();
}

void MainWindow::timerslot2()
{
    qDebug()<<"More";
}

开始时的输出:

In

每次点击输出:

In

点击3次后输出:

In
In
In
In

退出应用程序的输出:

In
In
In
In
More
More
More
More