0

我在连接到信号QMessageBox的插槽中创建了一个带有单个按钮“OK”的实例,并使用函数显示它,似乎计时器暂停,直到按下按钮并且盒子关闭。我希望创建本地事件循环并发送计时器消息,但是计时器被暂停(没有发出信号)。谁能解释一下?PS对不起我的英语。QTimertimeout()execexectimeout()

更新:示例代码:

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

1 回答 1

0

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

这将我们引向QObject源代码。执行 slot 函数后QMetaObject::activate,最后一步是重置信号的发送者:

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

这将重置QTimer状态,并再次开始倒计时。我认为这是确保定时器回调按顺序调用的常识方法——就像大多数 UI 库中的定时器一样,而不是在同一个定时器中并行调用。

因为exec()会阻塞定时器回调,QTimer不会被重置并且回调不会被再次调用(直到函数恢复,并QTimer得到它的重置)。

你有几种方法来处理这个:

1)如果您不希望您的函数阻塞,并且您不需要模态对话框的结果来继续该函数 - 调用QMessageBox::open()而不是QMessageBox::exec()- 它不会阻止调用者函数。

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

于 2013-02-03T23:39:01.807 回答