我在连接到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;
}
答案 0 :(得分:0)
好吧,你可以看到事件循环正在运行,因为timer1
正在触发超时。从documentation您可以看到exec()
正在阻止调用 - 因此它将阻止调用方函数(QTimer插槽),直到对话框关闭。
这导致我们转到QObject
源代码。执行插槽功能后,在QMetaObject::activate
中,最后一步是重置信号的发送方:
QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender);
这将重置QTimer
状态,它将再次开始倒计时。我认为这是确保按顺序调用定时器回调的常识性方法 - 如大多数UI库中的定时器,而不是相同定时器中的并行调用。
由于exec()
将阻止定时器回调,QTimer
将不会被重置,并且不会再次调用回调(直到函数恢复,并且QTimer
重置)。
您有几种方法可以解决这个问题:
1)如果你不希望你的功能被阻止,并且你不需要模态对话的结果来继续这个功能 - 调用QMessageBox::open()
而不是QMessageBox::exec()
- 它不会阻止来电者功能。
2)如果您需要对话框的结果来继续该功能,并且您不想停止计时器回调,那么天真的方法是通过调用QTimer
和{{{}来手动重置QTimer::stop()
1}}在进入回调函数时顺序执行。