我做了一个读卡工具,有个连续读卡功能,读卡时还得一直寻卡,寻到卡后才能读;为避免死等,可以在连续读卡中去停止读卡,所以需要写一个线程用来读卡;
我使用的是moveToThread方式;
我有个窗口程序,有个读卡类;我希望读卡时是个线程在操作,所以我在窗口上定义了一个线程对象:
//在类中定义一个QThread对象m_thread
QThread m_thread;`
并把读卡器类设置到线程上并启动线程:
// 启动读卡线程
readIdCard.moveToThread(&m_thread);
m_thread.start();
读卡器类中,新增一个定时器,并且设置定时器超时就掉一下读卡接口readCardOnce;
timer = new QTimer(this);
timer->setInterval(500);
connect(timer, SIGNAL(timeout()), this, SLOT(readCardOnce()));
readCardOnce接口:
if(!m_isRead){ // 设此标记是为了能即使停定时器
traceLogLib.outPutMsg(QtDebugMsg, "ReadIdCard::readerCardOnce invoke end. m_isRead = false");
return;
}
// 寻卡
。。。省略
if(寻卡成功)
{
// 读取身份证信息
。。。省略
}
窗口和读卡线程是靠信号和槽连接的:思路是信号和槽的关联都在窗口里去设置,因为窗口已经有读卡类了,且窗口的头文件无法在其他文件里引入(QT的限制);如下:做发射读卡信号,那边读卡成功后会发射读卡结果的信号,这边readCardOnceResult进行处理数据即可;
// 开关端口
connect(this, SIGNAL(openAndClose()), &readIdCard, SLOT(openAndClosePort())); // 关联信号和槽
connect(&readIdCard, SIGNAL(openAndCloseResult(int)), this, SLOT(openAndCloseResult(int))); // 处理打开设备结果
// 一次读卡
connect(this, SIGNAL(readCardOnce()), &readIdCard, SLOT(readCardOnce())); // 关联信号和槽
connect(&readIdCard, SIGNAL(readCardOnceResult(int)), this, SLOT(readCardOnceResult(int)));
//连续读卡
connect(this, SIGNAL(readCardTimes()), &readIdCard, SLOT(readCardTimes())); // 关联信号和槽
connect(this, SIGNAL(stopReadCard()), &readIdCard, SLOT(stopReadCard())); // 关联信号和槽
connect(&readIdCard, SIGNAL(stopReadCardResult()), this, SLOT(stopReadCardResult()));
点击开始读卡后,窗口给读卡类发射开始读卡信号,读卡器类的对应接口readCardTimes启动读卡定时器:
timer->start();
正在寻卡时,点了停止读卡,会触发停止读卡信息,由读卡器类的接口stopReadCard进行停止定时器:
if(timer->isActive()){
traceLogLib.outPutMsg(QtDebugMsg, "暂停定时器。。。");
timer->stop();
if (timer->isActive()) {
traceLogLib.outPutMsg(QtDebugMsg, "暂停定时器成功");
}
}
窗口点右上角X关掉时,需要停掉线程:
通过重写void closeEvent(QCloseEvent*);实现的:
void QtWidgetsApplication32::closeEvent(QCloseEvent *e)
{
//窗口关闭时弹出的提示窗口
QMessageBox msgBox;
msgBox.setText("提示");
msgBox.setInformativeText("确认退出?");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
int ret = msgBox.exec();
if (ret == QMessageBox::Ok) {
//若用户点击确认,则接收这个事件,当前窗口会关闭
e->accept();
m_thread.quit(); // 退出线程
}
else {
//若用户点击取消,则忽略这个事件,当前窗口不会关闭
e->ignore();
}
}