在我们快速触发一个信号,但是它的槽函数比较耗,这个时候很有可能出现并发情况。
解决方法:每次发送信号前将数据备份,然后在发送信号位置前使用标志位,防止下一次进入,然后槽函数结束后判断备份的数据和传进来的数据是否一致,不一致则用备份数据重新执行标志位里面的操作。
#ifndef WIDGET_H
#define WIDGET_H
#include <QtWidgets>
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
void control(QString text);
signals:
void textchange(QString text);
void textfinish(QString text);
private slots:
void slotIntext(QString text);
void slotOuttext(QString val);
void slotTextFinish(QString text);
void slotCleartext();
private:
bool m_flag;
QString m_text;
QPushButton* m_btn;
QLineEdit* m_edit;
QTextEdit* m_inedit;
QTextEdit* m_outedit;
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
m_flag = false;
m_edit = new QLineEdit(this);
m_inedit = new QTextEdit(this);
m_outedit = new QTextEdit(this);
m_btn = new QPushButton("清空",this);
QGridLayout* lay = new QGridLayout(this);
lay->addWidget(m_edit,0,0);
lay->addWidget(m_inedit,2,0);
lay->addWidget(m_outedit,3,0);
lay->addWidget(m_btn,4,0);
this->setLayout(lay);
m_edit->setPlaceholderText("写入文本:");
m_inedit->setPlaceholderText("输入文本:");
m_outedit->setPlaceholderText("输出文本:");
connect(m_edit,SIGNAL(textEdited(QString)),this,SLOT(slotIntext(QString)));
connect(this,SIGNAL(textchange(QString)),this,SLOT(slotOuttext(QString)));
connect(this,SIGNAL(textfinish(QString)),this,SLOT(slotTextFinish(QString)));
connect(m_btn,SIGNAL(clicked()),this,SLOT(slotCleartext()));
}
Widget::~Widget()
{
}
//快速且多次触发的函数
void Widget::slotIntext(QString text)
{
m_inedit->setText("输入文本:"+text);
#if 0 //并发场景
//当快速点击时,可能会出现信号对应的槽函数处理不过来,造成下次不会进入if语句中
if (!m_flag)
{
control(text);
}
#else //防并发场景
m_text = text;
//当快速点击时,可能会出现信号对应的槽函数处理不过来,造成下次不会进入if语句中
if (!m_flag)
{
control(text);
}
#endif
}
void Widget::control(QString text)
{
m_flag = true;
emit textchange(text);
}
void Widget::slotOuttext(QString val)
{
//模拟耗时操作
QTime dieTime = QTime::currentTime().addMSecs(100);
while( QTime::currentTime() < dieTime )
QApplication::processEvents(QEventLoop::AllEvents, 100);
m_outedit->setText("输出文本:"+val);
emit textfinish(val); //通知耗时操作处理完毕
}
void Widget::slotTextFinish(QString text)
{
#if 0 //并发场景
m_flag = false;
#else //防并发场景
m_flag = false;
if (m_text != text)
control(m_text);
#endif
}
void Widget::slotCleartext()
{
m_edit->clear();
}
注意:此场景只适合获取最新的操作,且中间操作不需要管。当然如果我们要获取每一次操作,且保证顺序也不能并发,可以使用队列,流程如下:1、每次发送信号前新值存入队列。2、存入队列后,加条件语句判断是否再次输入,如果条件语句内没有执行完毕是不能再次进入条件语句,如果执行完毕可以再次进入条件语句,然后执行内部操作。3、条件语句中内部操作执行完毕后,删除队列中当前执行的值。4、然后循环从队列取值执行内部操作。