1

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

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

QTimer* timer = new QTimer;

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

timer->start(100);

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

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

抛开这个循环有多愚蠢,我们看到我们永远不会完成对插槽的处理,并且计时器的后续超时将继续堆积到执行队列中。一切都很好,应该是这样。

接下来不应该出现的情况是:由于 QEventLoop 确保我们的应用程序在插槽无意识地闲置时保持响应,我们可以制作一个按钮及其 clicked() 插槽,如下所示:

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

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

我唯一的问题是:WTF?!为什么手动重新启动计时器可以使其进入插槽附加时间?我在freenode上问过,但我得到的唯一答案是“它应该是”

4

1 回答 1

3

我试过这个,每次点击都会创建另一个“输入”行。

主事件循环无法处理另一个事件,因为我们被困在一个新的事件循环中。

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

  • 当调用下一个事件循环并且不再处理任何排队的事件时,主事件循环将被卡住。
  • 计时器本身也不会再排队任何事件,因为排队本身将在现在卡住的主事件循环中完成。计时器不在其自己的事件循环中运行(这就是 Qtimers 不是精确计时器的原因)。
  • 一旦单击按钮,新的事件循环就会检查计时器是否timeout()应该生成事件。
  • 一旦处理了新事件,我们就会再次陷入另一个事件循环......
  • 这将一直持续到我们退出应用程序。
  • 退出应用程序时,我们看到循环反转并调用第二个插槽,就像我们单击按钮并进入第一个插槽一样频繁

代码:

#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
于 2014-11-13T15:51:18.630 回答