QMessageBox暂停QTimer

时间:2013-02-03 19:00:11

标签: qt

我在连接到QMessageBox信号QTimer的插槽中创建了一个timeout()个实例,单个按钮“确定”并使用exec函数显示它,似乎计时器停止,直到按下按钮,盒子关闭。我期望exec创建本地事件循环和调度计时器消息,但是计时器停止(没有信号timeout()发出)。谁能解释一下? P.S抱歉我的英文。

更新: 示例代码:

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

  connect(tm1,SIGNAL(timeout()),this,SLOT(tslot1()));
  connect(tm2,SIGNAL(timeout()),this,SLOT(tslot2()));
  tm1->start(1000);
  tm2->start(1000);
}

void MainWindow::tslot1(void)
{
  static int cnt;
  qWarning(QString("slot 1 called %1 time(s)").arg(++cnt).toAscii().data());
}

void MainWindow::tslot2(void)
{
  static int cnt;
  qWarning(QString("slot 2 called %1 time(s)").arg(++cnt).toAscii().data());
  if (3==cnt)
  {
    QMessageBox *mb=new QMessageBox(QMessageBox::Critical,tr("Error"),tr("tm2 halted !"),QMessageBox::Ok,this);
    mb->exec();
  }
}

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

1 个答案:

答案 0 :(得分:0)

好吧,你可以看到事件循环正在运行,因为timer1正在触发超时。从documentation您可以看到exec()正在阻止调用 - 因此它将阻止调用方函数(QTimer插槽),直到对话框关闭。

这导致我们转到QObject源代码。执行插槽功能后,在QMetaObject::activate中,最后一步是重置信号的发送方:

QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);

这将重置QTimer状态,它将再次开始倒计时。我认为这是确保按顺序调用定时器回调的常识性方法 - 如大多数UI库中的定时器,而不是相同定时器中的并行调用。

由于exec()将阻止定时器回调,QTimer将不会被重置,并且不会再次调用回调(直到函数恢复,并且QTimer重置)。

您有几种方法可以解决这个问题:

1)如果你不希望你的功能被阻止,并且你不需要模态对话的结果来继续这个功能 - 调用QMessageBox::open()而不是QMessageBox::exec() - 它不会阻止来电者功能。

2)如果您需要对话框的结果来继续该功能,并且您不想停止计时器回调,那么天真的方法是通过调用QTimer和{{{}来手动重置QTimer::stop() 1}}在进入回调函数时顺序执行。