QSignalBlocker在构造函数中阻塞信号,在析构函数中它将状态重置为构造函数运行前的状态。
QSignalBlocker用来代替blockSignals()。当使用blockSignals()来阻塞信号时,总要成对使用blockSignals(true)和blockSignals(false)。一不小心少写一个则信号一直阻塞后果难料,使用QSignalBlocker代替则不会有问题。当QSignalBlocker对象出了作用域范围后,根据C++规则会自动调用其析构函数,从而将状态重置为构造函数运行前的状态。如下代码:
#include "QSignalBlockerDemo.h"
#include <QDebug>
#include <QDateTime>
#include<QPushButton>
QSignalBlockerDemo::QSignalBlockerDemo(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
connect(ui.pushButton, &QAbstractButton::clicked, this, &QSignalBlockerDemo::blockTimer);
connect(&timer, &QTimer::timeout, this, &QSignalBlockerDemo::onTimer);
timer.start(1000);
}
void QSignalBlockerDemo::onTimer()
{
qDebug() << "xxxxxxx" << QDateTime::currentDateTime();
}
void QSignalBlockerDemo::blockTimer()
{
QSignalBlocker blocker(timer);
QEventLoop eventloop;
QTimer::singleShot(5000, &eventloop, SLOT(quit()));
eventloop.exec();
qDebug() << QString::fromLocal8Bit("过了5秒");
}
输入结果如下:
可以看到,当单击按钮时,信号被阻塞,从而使每隔1s的定时器timer的timeout信号失效,等5s后QEventLoop类的eventloop事件循环退出后,blockTimer()函数执行完,导致QSignalBlocker类型的对象eventloop被析构,之后因为没有QSignalBlocker类型信号阻塞器对象了,就不会再阻塞timer的timeout信号,程序继续每隔1s打印出日志。QEventLoop类使用参考
如下图,当我改变左边框的文字,右边的也会对应填写数据,当我在右边填写文字的时候,左边也跟着变化。
它的逻辑图如下:
这个时候我们可能就发现问题了,如果是信号的话,就会走1-2-3-4-5-2-3... 这样无限循环下去,我们想一下,要是能切断信号4,就可以左边写什么右边写什么,同理切断2的信号,就可以完成右边写什么,左边就写什么了。
当然你直接使用textChanged 也会判断,至少会多发一个消息。如果只是接受到信号就发送的话,也就会出现死循环的问题;实现右边写什么,左边就写什么的功能就会失败,所以我们要用下面的方式来写:
void MainWindow::on_lineEditleft_textChanged(const QString &arg1)
{
ui->lineEditright->blockSignals(true);
ui->lineEditright->setText(arg1);
ui->lineEditright->blockSignals(false);
}
void MainWindow::on_lineEditright_textChanged(const QString &arg1)
{
ui->lineEditleft->blockSignals(true);
ui->lineEditleft->setText(arg1);
ui->lineEditleft->blockSignals(false);
}
效果图如下: