基于qt的教职工打卡 体系, qt教学
一、项目概述
1.1 项目名称
教职工打卡 体系(源代码已关注联系作者)
1.2 项目背景
本项目 一个综合应用程序,集成了人脸识别、串口通信、数据库操作等功能,可能用于考勤管理、用户注册等场景。
1.3 项目目标
开发一个具有人脸识别、用户注册、数据存储和串口控制功能的应用程序。
二、 体系架构
2.1 整体架构
项目采用模块化架构,主要分为 下面内容 几许模块:
界面模块:负责用户交互和界面显示,包括登录注册界面、主界面、人脸识别界面等。 人脸识别模块:与百度 AI 开放平台对接,实现人脸检测和注册功能。 数据库模块:使用 SQLite 数据库存储用户信息。 串口通信模块:与外部设备进行串口通信,实现设备控制。
2.2 模块关系
各模块之间通过接口进行交互,界面模块调用其他模块的功能,实现用户需求。
三、功能模块详细设计
3.1 界面模块
3.1.1 主界面(MainWindow)
功能描述:作为程序的入口,显示应用程序的主要界面。 代码实现:在 in.cpp中创建MainWindow对象并显示。
cpp
运行
#include " inwindow.h" #include <QApplication> int in(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }3.1.2 注册界面(zhucewindow)
功能描述:用户可以在该界面进行注册和登录操作,同时可以查询用户信息并显示在表格中。 代码实现:在zhucewindow.cpp中实现注册、登录和查询功能。
cpp
运行
// 注册界面构造函数,初始化数据库和表格 zhucewindow::zhucewindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::zhucewindow) { ui->setupUi(this); databasetwo = QSqlDatabase::addDatabase("QSQLITE"); databasetwo.setDatabaseName("teacher_two.db"); if (!databasetwo.open()) { qDebug() << "Error: Failed to connect database"; } else { qDebug() << "success......" ; } // 创建学生表 QSqlQuery sql_query(databasetwo); QString create_sql = "create table student (name varchar(30) pri ry key,zhanghao varchar(60),pass text,pass_down text,pass_up_to_down text)"; sql_query.prepare(create_sql); if(!sql_query.exec()) { qDebug() << "Error: Fail to create table." ; } else { qDebug() << "Table created!"; } } // 登录按钮点击事件 void zhucewindow::on_pushButton_clicked() { // 获取用户输入 QString name = ui->lineEdit->text(); QString passwd = ui->lineEdit_2->text(); QString passwd2 = ui->lineEdit_3->text(); // 查询指定用户名的记录 QSqlQuery sql_query(databasetwo); QString select_sql = "SELECT name, zhanghao FROM student WHERE name = :name"; sql_query.prepare(select_sql); sql_query.bindValue(":name", name); if (!sql_query.exec()) { qDebug() << "查询失败:" << sql_query.lastError(); } else if (sql_query.next()) { // 找到记录 QString dbName = sql_query.value(0).toString(); QString dbPass = sql_query.value(1).toString(); // 比较密码 if (passwd == dbPass) { qDebug() << "登录成功,跳到主界面"; souxun(); } else { qDebug() << "姓名与账号不匹配"; ui->label_9->setText("姓名与账号不匹配" ); ui->label_9->setStyleSheet("color: green;"); QTimer::singleShot(5000, [=](){ ui->label_9->setText(""); }); } } else { qDebug() << "用户不存在"; ui->label_9->setText("用户不存在"); ui->label_9->setStyleSheet("color: green;"); QTimer::singleShot(5000, [=](){ ui->label_9->setText(""); }); } } // 查询用户信息 void zhucewindow::souxun(){ QString name = ui->lineEdit->text(); QSqlQuery sql_query(databasetwo); QString select_sql = "SELECT name, zhanghao ,pass,pass_down,pass_up_to_down FROM student WHERE name = :name"; sql_query.prepare(select_sql); sql_query.bindValue(":name", name); if (!sql_query.exec()) { qDebug() << "查询失败:" << sql_query.lastError(); ui->label_9->setText("查询失败,用户:" + name); ui->label_9->setStyleSheet("color: green;"); QTimer::singleShot(5000, [=](){ ui->label_9->setText(""); }); } else if (sql_query.next()) { // 找到记录 QString dbname = sql_query.value(0).toString(); QString dbzhanghao = sql_query.value(1).toString(); QString dbpass = sql_query.value(2).toString(); QString dbpass_down = sql_query.value(3).toString(); QString dbpass_up_to_down = sql_query.value(4).toString(); qDebug() << "名字:" << dbname << "小时"; qDebug() << "账号:" << dbzhanghao << "小时"; qDebug() << "开始 时刻:" << dbpass << "小时"; qDebug() << "结束 时刻:" << dbpass_down << "小时"; qDebug() << "上班 时刻:" << dbpass_up_to_down << "秒"; setupTableTab(dbname, dbzhanghao, dbpass,dbpass_down, dbpass_up_to_down); ui->label_9->setText("查询成功,用户:" + dbname); ui->label_9->setStyleSheet("color: green;"); QTimer::singleShot(5000, [=](){ ui->label_9->setText(""); }); } } // 设置表格表头 void zhucewindow::setupTableTab(const QString& name, const QString& account, const QString& checkinTime, const QString& checkoutTime, const QString& totalHours) { ui->tableWidget->setColumnCount(5); QStringList headers; headers << "姓名" << "账号" << "打卡 时刻"<<"结束 时刻"<<"上班总时"; ui->tableWidget->setHorizontalHeaderLabels(headers); ui->tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color: lightgray; }"); QFont font = ui->tableWidget->horizontalHeader()->font(); font.setBold(true); ui->tableWidget->horizontalHeader()->setFont(font); insertRecord(name, account, checkinTime, checkoutTime, totalHours); } // 插入记录到表格 void zhucewindow::insertRecord(const QString& name, const QString& account, const QString& checkinTime, const QString& checkoutTime, const QString& totalHours) { int row = ui->tableWidget->rowCount(); ui->tableWidget->insertRow(row); ui->tableWidget->setItem(row, 0, new QTableWidgetItem(name)); ui->tableWidget->setItem(row, 1, new QTableWidgetItem(account)); ui->tableWidget->setItem(row, 2, new QTableWidgetItem(checkinTime)); ui->tableWidget->setItem(row, 3, new QTableWidgetItem(checkoutTime)); ui->tableWidget->setItem(row, 4, new QTableWidgetItem(totalHours)); for(int col = 0; col < 5; col++) { ui->tableWidget->item(row, col)->setTextAlignment(Qt::AlignCenter); } }3.1.3 人脸识别界面(Window)
功能描述:支持人脸检测和注册功能,可选择相机、捕获图像、获取访问令牌等。 代码实现:在window.cpp中实现相机初始化、网络请求和人脸识别功能。
cpp
运行
// 人脸识别界面构造函数,初始化相机、网络和UI Window::Window(QWidget *parent) : QMainWindow(parent) , ui(new Ui::Window) , myCamera(nullptr) , viewfinder(nullptr) , i geCapture(nullptr) , nager(nullptr) , currentMode(FaceMode::Detect) , clientId("T3WpS2ouSdusYX8VXi4qlhT3") , clientSecret("WOdbUdrhvalhhKbbZNkoz6yeX5MHTpkk") , accessToken("") { ui->setupUi(this); initCamera(); initNetwork(); initUI(); qDebug() << "应用初始化完成"; } // 初始化相机 void Window::initCamera() { auto cameras = QCameraInfo::availableCameras(); if (cameras.isEmpty()) { qDebug() << "未检测到相机"; ui->comboBox->setEnabled(false); ui->pushButton->setEnabled(false); return; } for (const auto &camera : cameras) { ui->comboBox->addItem(camera.deviceName()); } ui->comboBox->setCurrentIndex(0); } // 初始化网络 void Window::initNetwork() { nager = new QNetworkAccessManager(this); connect( nager, &QNetworkAccessManager::finished, this, &Window::handleResponse); } // 初始化UI void Window::initUI() { ui->modeComboBox->addItem("人脸检测", static_cast<int>(FaceMode::Detect)); ui->modeComboBox->addItem("人脸注册", static_cast<int>(FaceMode::Register)); ui->modeComboBox->setCurrentIndex(0); userNameEdit = new QLineEdit(this); userIdEdit = new QLineEdit(this); groupIdEdit = new QLineEdit(this); groupIdEdit->setText("users"); userNameLabel = new QLabel("用户名:", this); userIdLabel = new QLabel("用户ID:", this); groupIdLabel = new QLabel("组ID:", this); registerButton = new QPushButton("人脸注册", this); ui->verticalLayout->addWidget(userNameLabel); ui->verticalLayout->addWidget(userNameEdit); ui->verticalLayout->addWidget(userIdLabel); ui->verticalLayout->addWidget(userIdEdit); ui->verticalLayout->addWidget(groupIdLabel); ui->verticalLayout->addWidget(groupIdEdit); ui->verticalLayout->addWidget(registerButton); userNameEdit->setVisible(false); userIdEdit->setVisible(false); groupIdEdit->setVisible(false); userNameLabel->setVisible(false); userIdLabel->setVisible(false); groupIdLabel->setVisible(false); registerButton->setVisible(false); connect(registerButton, &QPushButton::clicked, this, &Window::onRegisterButtonClicked); connect(ui->modeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Window::onModeChanged); } // 打开相机按钮点击事件 void Window::on_pushButton_clicked() { startCamera(); } // 启动相机 void Window::startCamera() { if (myCamera) { myCamera->stop(); delete myCamera; myCamera = nullptr; } if (i geCapture) { delete i geCapture; i geCapture = nullptr; } if (viewfinder) { delete viewfinder; viewfinder = nullptr; } QString cameraName = ui->comboBox->currentText(); auto cameras = QCameraInfo::availableCameras(); bool cameraFound = false; for (const auto &info : cameras) { if (info.deviceName() == cameraName) { myCamera = new QCamera(info, this); cameraFound = true; break; } } if (!cameraFound) { qDebug() << "无法创建相机对象: " << cameraName; return; } viewfinder = new QCameraViewfinder(ui->widget); if (!viewfinder) { qDebug() << "无法创建取景器"; delete myCamera; myCamera = nullptr; return; } myCamera->setViewfinder(viewfinder); viewfinder->resize(ui->widget->size()); viewfinder->show(); myCamera->start(); i geCapture = new QCameraI geCapture(myCamera); if (i geCapture) { connect(i geCapture, &QCameraI geCapture::i geCaptured, this, [this](int, const QI ge &img) { showI ge(img); }); } qDebug() << "相机已启动: " << cameraName; } // 显示图像 void Window::showI ge(const QI ge &i ge) { QPix p pix = QPix p::fromI ge(i ge); pix = pix.scaled(ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransfor tion); ui->label->setPix p(pix); QBuffer buffer(&lastI geData); buffer.open(QIODevice::WriteOnly); pix.toI ge().save(&buffer, "JPEG"); } // 获取访问令牌 QString Window::getAccessTokenFromBaidu() { if (clientId.isEmpty() || clientSecret.isEmpty()) { QMessageBox::critical(this, "配置错误", "clientId 或 clientSecret 为空,请检查配置"); return ""; } QString urlStr = QString("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%1&client_secret=%2") .arg(clientId) .arg(clientSecret); QUrl url(urlStr); QNetworkRequest request(url); request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win ; x ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x- -form-urlencoded"); QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); sslConfig.setProtocol(QSsl::TlsV1_2OrLater); sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); request.setSslConfiguration(sslConfig); nager->get(request); return ""; } // 人脸检测 void Window::faceDetect(const QByteArray &i geData) { if (accessToken.isEmpty() || i geData.isEmpty()) return; QUrl url("https://aip.baidubce.com/rest/2.0/face/v3/detect"); QUrlQuery query; query.addQueryItem("access_token", accessToken); url.setQuery(query); QJsonObject obj; obj["i ge"] = QString(i geData.toBase ()); obj["i ge_type"] = "BASE "; obj["face_field"] = "age,beauty,expression,gender"; QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); nager->post(request, QJsonDocument(obj).toJson()); } // 人脸注册 void Window::faceRegister(const QByteArray &i geData, const QString &userId, const QString &userName, const QString &groupId) { if (accessToken.isEmpty() || i geData.isEmpty() || userId.isEmpty()) return; QUrl url("https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"); QUrlQuery query; query.addQueryItem("access_token", accessToken); url.setQuery(query); QJsonObject obj; obj["i ge"] = QString(i geData.toBase ()); obj["i ge_type"] = "BASE "; obj["group_id"] = groupId; obj["user_id"] = userId; obj["user_info"] = userName; obj["quality_control"] = "NORMAL"; nager->post(request, QJsonDocument(obj).toJson()); }3.2 人脸识别模块
3.2.1 功能描述
与百度 AI 开放平台对接,实现人脸检测和注册功能。
3.2.2 代码实现
在window.cpp和 inwwindow.cpp中实现了获取访问令牌、人脸检测和注册的功能。
cpp
运行
// 获取访问令牌 QString Window::getAccessTokenFromBaidu() { if (clientId.isEmpty() || clientSecret.isEmpty()) { QMessageBox::critical(this, "配置错误", "clientId 或 clientSecret 为空,请检查配置"); return ""; } QString urlStr = QString("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%1&client_secret=%2") .arg(clientId) .arg(clientSecret); QUrl url(urlStr); QNetworkRequest request(url); request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win ; x ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x- -form-urlencoded"); QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); sslConfig.setProtocol(QSsl::TlsV1_2OrLater); sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); request.setSslConfiguration(sslConfig); nager->get(request); return ""; } // 人脸检测 void Window::faceDetect(const QByteArray &i geData) { if (accessToken.isEmpty() || i geData.isEmpty()) return; QUrl url("https://aip.baidubce.com/rest/2.0/face/v3/detect"); QUrlQuery query; query.addQueryItem("access_token", accessToken); url.setQuery(query); QJsonObject obj; obj["i ge"] = QString(i geData.toBase ()); obj["i ge_type"] = "BASE "; obj["face_field"] = "age,beauty,expression,gender"; QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); nager->post(request, QJsonDocument(obj).toJson()); } // 人脸注册 void Window::faceRegister(const QByteArray &i geData, const QString &userId, const QString &userName, const QString &groupId) { if (accessToken.isEmpty() || i geData.isEmpty() || userId.isEmpty()) return; QUrl url("https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"); QUrlQuery query; query.addQueryItem("access_token", accessToken); url.setQuery(query); QJsonObject obj; obj["i ge"] = QString(i geData.toBase ()); obj["i ge_type"] = "BASE "; obj["group_id"] = groupId; obj["user_id"] = userId; obj["user_info"] = userName; obj["quality_control"] = "NORMAL"; nager->post(request, QJsonDocument(obj).toJson()); }3.3 数据库模块
3.3.1 功能描述
使用 SQLite 数据库存储用户信息,包括用户姓名、账号、密码等。
3.3.2 代码实现
在zhucewindow.cpp和sqlitebase.cpp中实现了数据库的创建和操作。
cpp
运行
// 创建学生表 void SqliteBasic::createTable(){ QSqlQuery sqlQuery; QString createSql = QString("CREATE TABLE student ( id INT PRIMARY KEY NOT NULL, name TEXT NOT NULL, age INT NOT NULL)"); sqlQuery.prepare(createSql); if(!sqlQuery.exec()) { qDebug() << "Error: Fail to create table. " << sqlQuery.lastError(); } else { qDebug() << "Table created!"; } }3.4 串口通信模块
3.4.1 功能描述
与外部设备进行串口通信,实现设备控制。
3.4.2 代码实现
在windowone.cpp和windowtwo.cpp中实现了串口通信功能。
cpp
运行
// 发送LED控制指令 void Windowone::guan_d(){ qDebug() << "111.... 开始执行dakd函数"; if (!serialPort->isOpen()) { qDebug() << "222.... 串口未打开,尝试自动打开"; QString portName = "COM9"; serialPort->setPortName(portName); serialPort->setBaudRate(115200); serialPort->setDataBits(QSerialPort::Data8); serialPort->setParity(QSerialPort::NoParity); serialPort->setStopBits(QSerialPort::OneStop); serialPort->setFlowControl(QSerialPort::NoFlowControl); if (serialPort->open(QIODevice::ReadWrite)) { qDebug() << "444.... 串口打开成功"; updateConnectionStatus(true); ui->txtReceive->append(QString("[%1] 串口自动打开: %2 @ %3bps") .arg(for tTimestamp()) .arg(portName) .arg("115200")); } else { qDebug() << "555.... 串口打开失败: " << serialPort->errorString(); ui->txtReceive->append(QString("[%1] 串口自动打开失败: %2") .arg(for tTimestamp()) .arg(serialPort->errorString())); return; } } else { qDebug() << "222.... 串口已打开, 情形正常"; } QString text = "{"led":1}"; text += " "; QByteArray data = text.toUtf8(); qDebug() << "666.... 准备发送数据: " << data; if (serialPort->isOpen()) { qint bytesWritten = serialPort->write(data); qDebug() << "777.... 发送字节数: " << bytesWritten; if (bytesWritten == -1) { qDebug() << "888.... 数据发送失败,错误信息:" << serialPort->errorString(); ui->txtReceive->append(QString("[%1] 发送失败: %2").arg(for tTimestamp()).arg(serialPort->errorString())); } else { totalBytesSent += bytesWritten; ui->lblStats->setText(QString("发送: %1 字节 | 接收: %2 字节") .arg(totalBytesSent) .arg(totalBytesReceived)); ui->txtReceive->append(QString("[%1] 发送LED控制指令: %2,等待响应...") .arg(for tTimestamp()) .arg(currentCodec->toUnicode(data))); if (serialPort->waitForReadyRead(500)) { qDebug() << "888.... 收到单片机响应,等待on_readyRead()处理"; } else { qDebug() << "888.... 未收到单片机响应"; ui->txtReceive->append(QString("[%1] 警告: 未收到单片机响应,可能未正确接收或处理指令") .arg(for tTimestamp())); } } } else { qDebug() << "888.... 串口 情形异常,无法发送数据"; ui->txtReceive->append(QString("[%1] 发送失败: 串口 情形异常").arg(for tTimestamp())); } qDebug() << "999.... dakd函数执行完毕"; }四、数据库设计
4.1 数据库选择
使用 SQLite 数据库, 由于它轻量级、易于集成,适合小型应用程序。
4.2 数据表设计
4.2.1 学生表(student)
name | varchar(30) | 学生姓名,主键 |
zhanghao | varchar(60) | 学生账号 |
pass | text | 密码 |
pass_down | text | 结束 时刻 |
pass_up_to_down | text | 上班总时长 |
五、开发环境
5.1 操作 体系
Windows
5.2 开发工具
Qt Creator MinGW(编译器)
5.3 依赖库
Qt 库 百度 AI 开放平台 SDK
六、部署与运行
6.1 编译项目
使用 Qt Creator 打开test_y3.pro文件,配置好编译器, 接着进行编译。
6.2 运行项目
编译成功后,在 Qt Creator 中点击运行按钮,或者在生成的可执行文件目录下运行程序。
6.3 注意事项
确保相机设备正常 职业,以便进行人脸识别。 确保 SQLite 数据库文件teacher_two.db存在, 并且有读写权限。 确保网络连接正常,以便获取百度 AI 开放平台的访问令牌。
七、测试 规划
7.1 功能测试
测试注册、登录功能,确保用户信息可以正确存储和验证。 测试人脸识别功能,包括人脸检测和注册,确保与百度 AI 开放平台的对接正常。 测试串口通信功能,确保可以正常发送和接收数据。
7.2 性能测试
测试应用程序的响应 时刻,确保在高并 况下不会出现卡顿现象。 测试数据库的读写性能,确保数据操作的效率。
八、维护与扩展
8.1 代码维护
遵循代码规范,保持代码的可读性和可维护性。 定期对代码进行重构,优化代码结构。
8.2 功能扩展
可以添加更多的人脸识别功能,如人脸比对、人脸搜索等。 可以添加更多的数据库表,存储更多的用户信息。 可以添加更多的串口设备,实现更多的设备控制功能。
九、附录
9.1 代码文件列表
test_y3/ in.cpp | 主程序入口 |
test_y3/zhucewindow.cpp | 注册界面实现 |
test_y3/window.cpp | 人脸识别界面实现 |
test_y3/sqlitebase.cpp | 数据库操作实现 |
test_y3/ inwwindow.cpp | 主窗口实现 |
test_y3/windowtwo.cpp | 串口通信界面实现 |
test_y3/windowone.cpp | 串口通信功能实现 |