测试读卡器和芯片时,执行一系列卡片APDU命令才能测试卡片是否正常,为了方便快速测试,希望根据脚本自动执行完所有命令;
效果如下:
1.加载脚本并设置到QTextBrowser中展示(文件读写不错的帖子:https://blog.csdn.net/HuanBianCheng27/article/details/125802513?spm=1001.2014.3001.5506)
点击选择脚本后代码如下:
// 选择脚本
void ICTestTools::on_selectScript_clicked() {
scriptPath = QFileDialog::getOpenFileName(this, "打开脚本文件", "D:/"); // 弹出对话框
ui.scriptPathlabel->setText(scriptPath); // 讲路径放到label中展示
readCardThread.path = scriptPath;
// 读取内容放到textBrowser中
QFile file(scriptPath);
// 设置打开方式
file.open(QIODevice::ReadOnly);
// QByteArray array = file.readAll(); // 一次读取所有文件内容
QByteArray array;
int lineCount = 0;
while (!file.atEnd()) {
array += file.readLine();
lineCount++;
}
ui.scriptCount->setText(QString::number(lineCount, 10));
// 将文件内容设置到textBrowser中
ui.scriptTxt->setText(array);
// 关闭文件
file.close();
}
file.readAll();是一次读取所有文件内容;
我希望知道每行的命令是什么,还有一共多少行,所以按行进行的读取(file.readLine());
2.新增线程执行脚本每行的命令;
新增ReadCardThread线程来执行具体脚本中的命令,执行命令中也可以选择停止执行;
.h
#ifndef THREAD01_H
#define THREAD01_H
#include <QThread>
#include <QMutex>
class ReadCardThread : public QThread
{
Q_OBJECT;
public:
ReadCardThread();
void startThread(); //开启线程
void stop(); //停止线程
void loadScript(); // 加载脚本
QString path; // 脚本路径
QList<QByteArray> baList; // 脚本内容列表
int lineCount = 0;
signals:
void runScriptLine(int ret);
protected:
void run(); //线程主执行函数
private:
volatile bool stopped; //线程停止位
QMutex m_mutex; //互斥锁
};
#endif // THREAD01_Hcpp
.cpp
#include "ReadCardThread.h"
#include <QFileDialog>
#include <QDebug>
#include <iostream>
#include <Windows.h>
using namespace std;
ReadCardThread::ReadCardThread()
{
stopped = false;
}
void ReadCardThread::loadScript()
{
// 加载脚本
QFile file(path);
// 设置打开方式
file.open(QIODevice::ReadOnly);
QByteArray array;
lineCount = 0;
while (!file.atEnd()) {
baList.append(file.readLine());
lineCount++;
}
// 关闭文件
file.close();
}
void ReadCardThread::run()
{
// 加载脚本
loadScript();
int i = 0;
while (!stopped && i < lineCount) {
emit runScriptLine(i);
Sleep(200);
i++;
}
//exec();
}
void ReadCardThread::startThread()
{
m_mutex.lock();
stopped = false;
m_mutex.unlock();
start();
}
void ReadCardThread::stop()
{
m_mutex.lock();
stopped = true;
m_mutex.unlock();
}
调用的exe中:
ReadCardThread readCardThread; 声明一个线程实例
// 线程读卡设置高亮
connect(&readCardThread, SIGNAL(runScriptLine(int)), this, SLOT(SetLineColor(int))); 绑定高亮某行命令的信号,如图
点击开始测试后,启动线程readCardThread.startThread(); 具体代码如下
// 开始跑脚本
void ICTestTools::on_startRunScript_clicked() {
ui.scriptTxt->moveCursor(QTextCursor::Start); // 光标回到初始位置
loginDoc = ui.scriptTxt->document();
loginDocNum = loginDoc->blockCount();//返回文档中的文本块的数量,回车符是一个block
// 1.清掉之前的设置
extraSelections.clear();
// 2.重置为黑色
for (int i = 0; i < loginDocNum; i++) {
QTextEdit::ExtraSelection selection1;
selection1.cursor = QTextCursor(loginDoc->findBlockByNumber(i)); // 选择第11行(假设行号从0开始)
selection1.cursor.select(QTextCursor::LineUnderCursor);
selection1.format.setForeground(Qt::black);
// 应用额外的选择
extraSelections.append(selection1);
}
ui.scriptTxt->setExtraSelections(extraSelections);
this->repaint(); // 重绘
// 3.起执行脚本的线程
readCardThread.startThread();
}
高亮设置的代码:当线程执行命令时,会把执行好的行号通过runScriptLine信号发到主进程中,进程进行如下设置;repaint是实时刷新的关键(知识获取来源:https://zhuanlan.zhihu.com/p/612034860?utm_id=0);
ui.scriptTxt->moveCursor(QTextCursor::Down) 可以让QTextBrowser有自动往下滚动的效果,不过我目前还没跳好,和我的高亮不是很一致;还得再研究研究;https://doc.qt.io/qt-5/qdesignerformwindowcursorinterface.html
```cpp
void ICTestTools::SetLineColor(int lineNum) {
if (lineNum > 0) {
extraSelections[lineNum-1].cursor = QTextCursor(loginDoc->findBlockByNumber(lineNum-1));
extraSelections[lineNum-1].cursor.select(QTextCursor::LineUnderCursor);
// 设置选择的格式(比如,蓝色背景)
extraSelections[lineNum-1].format.setForeground(Qt::black); // 上一行重置为黑色
}
// 设置选择范围
/* QTextEdit::ExtraSelection selection = extraSelections[lineNum];*/
extraSelections[lineNum].cursor = QTextCursor(loginDoc->findBlockByNumber(lineNum)); // 选择第11行(假设行号从0开始)
extraSelections[lineNum].cursor.select(QTextCursor::LineUnderCursor);
// 设置选择的格式(比如,蓝色背景)
// selection.format.setBackground(Qt::green); // 设置背景
extraSelections[lineNum].format.setForeground(Qt::green);
// 光标移动
ui.scriptTxt->moveCursor(QTextCursor::Down);
// ui.scriptTxt->moveCursor(QTextCursor::NextRow);
// 应用额外的选择
ui.scriptTxt->setExtraSelections(extraSelections);
this->repaint(); // 重绘
}
以下也可以设置滚动,需要计算每次滚动多少
// 设置滚动
int countLine = ui.scriptTxt->toPlainText().count();
QScrollBar* bar = ui.scriptTxt->verticalScrollBar();
ui.scriptTxt->verticalScrollBar()->setValue(bar->value() + num);