// MainWidget.cpp #include "MainWidget.h" void onThreadFinished(QThread* thread, ClientHandler* handler) { qDebug() << "Thread finished. Deleting handler and thread."; handler->deleteLater(); thread->deleteLater(); } // 初始化 UI 组件和服务器 MainWidget::MainWidget(QWidget* parent) : QWidget(parent), nextClientId(1), manualSend(false), isSendingAll(false), lastClickedGetPicCamIndex(-1), lastClickedGetPicDevIndex(-1), lastClickedGetVideoCamIndex(-1), lastClickedGetVideoDevIndex(-1), mServiceProvider(new ServiceProvider(this)), mdnsTimer(new QTimer(this)), httpClient(new HttpClient(this)) #if TEST_UDP_BROADCAST ,multicastSocket(new QUdpSocket(this)), multicastTimer(new QTimer(this)) #endif { leftLens_imageLabel = new QLabel(this); rightLens_imageLabel = new QLabel(this); videoLabel = new QLabel(this); frontFuncConfigLineEdit = new QLineEdit(this); backFuncConfigLineEdit = new QLineEdit(this); licenseHwInfoEdit = new QTextEdit(this); UuidHwInfoEdit = new QTextEdit(this); setupUI(); // 打印线程池状态信息 setupTimerForThreadPoolInfo(); server = new QTcpServer(this); //FactoryToolSendGetUuidToHttpServer(); //FactoryToolSendGetLicenseToHttpServer(); //FactoryToolSendPostComfirmToHttpServer(); //FactoryToolSendPostTestToHttpServer(); //FactoryToolSendPostLicenseToHttpServer(); connect(server, &QTcpServer::newConnection, this, [this]() { // 检查是否有挂起的连接 while (server->hasPendingConnections()) { QTcpSocket* socket = server->nextPendingConnection(); int clientId = nextClientId++; qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; qDebug() << "> A client is connected. ID:" << clientId; qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; stopMdnsService(); connectedClientsCount++; updateServerButtonText(); QTimer* timer = new QTimer(this); timer->setSingleShot(true); clientTimers[clientId] = timer; // 连接定时器超时信号到槽函数 connect(timer, &QTimer::timeout, this, [this, clientId]() { //qDebug() << "Timeout occurred for client ID:" << clientId; for (ClientHandler* handler : clients) { if (handler->getClientId() == clientId) { bool invoked = QMetaObject::invokeMethod(handler, "onTimeout", Qt::DirectConnection); if (!invoked) { qWarning() << "Failed to invoke onTimeout for client ID:" << clientId; } } } }); QThread* thread = new QThread(this); ClientHandler* handler = new ClientHandler(socket, frontBoardOneClickTest, frontBoardTest, frontBoardFuncConfig, frontBoardDevInfoJson, frontBoardLicenseJson, backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson, getPicJson, getVideoJson, clientId, nullptr); // 将 ClientHandler 移动到线程池中的线程 handler->moveToThread(thread); // 当线程结束时删除 handler connect(thread, &QThread::finished, this, [=]() { onThreadFinished(thread, handler); }); // 将sendData信号连接到主线程中的槽上 connect(handler, &ClientHandler::sendData, this, [socket](const QByteArray& data) { /*socket->write(data); socket->flush();*/ //qDebug() << "---------------------data.size():" << data.size(); QByteArray prefix; QDataStream stream(&prefix, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << quint32(0x55AA55AA); stream << quint16(0x0420); stream << quint32(data.size()); prefix.append(data); qDebug() << "Sending data:" << prefix.toHex(); socket->write(prefix); socket->flush(); }); connect(handler, &ClientHandler::startTimeout, this, [this, clientId](int timeout) { this->onStartTimeout(clientId, timeout); }); // 启动新的线程 thread->start(); clients.append(handler); clients_1[clientId] = handler; clientThreads[clientId] = thread; connect(handler, &ClientHandler::statusUpdated, this, &MainWidget::onStatusUpdated); connect(handler, &ClientHandler::clientDisconnected, this, &MainWidget::onClientDisconnected); connect(handler, &ClientHandler::allItemsProcessed, this, &MainWidget::onAllItemsProcessed); connect(handler, &ClientHandler::selectClientDisconnected, this, &MainWidget::onDisconnectClient); // 创建 DataHandler 对象并连接信号 DataHandler* dataHandler = new DataHandler(leftLens_imageLabel, rightLens_imageLabel, videoLabel, licenseHwInfoEdit, &devInfoLineEdits, this); connect(handler, &ClientHandler::dataReceived, dataHandler, &DataHandler::handleData); connect(dataHandler, &DataHandler::statusUpdated, this, &MainWidget::onStatusUpdated); connect(handler, &ClientHandler::startReadTimer, this, &MainWidget::startClientReadTimer); connect(handler, &ClientHandler::stopReadTimer, this, &MainWidget::stopClientReadTimer); // 创建和管理定时器 QTimer* readTimer = new QTimer(this); connect(readTimer, &QTimer::timeout, handler, &ClientHandler::onTimeoutRead); // readTimer->start(10); // 每 10ms 触发一次 // 将定时器存储到哈希表中,方便管理 clientReadTimers[clientId] = readTimer; connect(handler, &ClientHandler::sendDataToSomeClient, this, &MainWidget::sendDataToClient); } }); connect(httpClient, &HttpClient::requestFinished, this, &MainWidget::onHttpRequestFinished); connect(httpClient, &HttpClient::requestError, this, &MainWidget::onHttpRequestError); threadStatusTimer = new QTimer(this); connect(threadStatusTimer, &QTimer::timeout, this, &MainWidget::onCheckThreadStatus); //threadStatusTimer->start(100); // 每100ms检查一次线程状态 connectionStatusCheckTimer = new QTimer(this); connect(connectionStatusCheckTimer, &QTimer::timeout, this, &MainWidget::onCheckConnectionStatus); //connectionStatusCheckTimer->start(100); // 每100ms检查一次连接状态 connect(mdnsTimer, &QTimer::timeout, this, &MainWidget::startMdnsService); #if TEST_UDP_BROADCAST // 设置组播地址 QHostAddress groupAddress("224.0.0.251"); quint16 port = 5353; // 绑定UDP套接字 if (!multicastSocket->bind(QHostAddress::AnyIPv4, port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) { qWarning() << "Failed to bind multicast socket"; } // 加入组播组 bool joined = multicastSocket->joinMulticastGroup(groupAddress); if (!joined) { qWarning() << "Failed to join multicast group"; } // 定期发送组播消息 connect(multicastTimer, &QTimer::timeout, this, &MainWidget::sendMulticastMessage); multicastTimer->start(1000); // 每秒发送一次组播消息 #endif } MainWidget::~MainWidget() { #if TEST_UDP_BROADCAST multicastTimer->stop(); multicastSocket->leaveMulticastGroup(QHostAddress("224.0.0.251")); multicastSocket->close(); #endif if (mdnsTimer->isActive()) { mdnsTimer->stop(); } delete mdnsTimer; stopMdnsService(); for (auto timer : clientReadTimers) { timer->stop(); delete timer; } clientReadTimers.clear(); for (ClientHandler* handler : clients) { handler->deleteLater(); } server->close(); for (auto thread : clientThreads) { thread->quit(); thread->wait(); delete thread; } clientThreads.clear(); for (auto handler : clients_1) { handler->deleteLater(); } clients_1.clear(); for (auto timer : clientTimers) { timer->stop(); delete timer; } clientTimers.clear(); if (server->isListening()) { server->close(); } qDebug() << "MainWidget destroyed"; } // 服务器响应 void MainWidget::onHttpRequestFinished(const QJsonObject& response) { isRequestSuccessful = 0; if (response.contains("msg") && response["msg"].toString() == "ok") { if (response.contains("data") && response["data"].isObject()) { licenseDataArray = response["data"].toObject(); isRequestSuccessful = 1; } } else isRequestSuccessful = 2; } void MainWidget::onHttpRequestError(const QString& errorString) { qWarning() << "HTTP request failed:" << errorString; isRequestSuccessful = 2; } QString generateRandomRequestID() { const QString possibleCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~"; int length = QRandomGenerator::global()->bounded(1, 33); // 生成长度在1到32之间 QString randomString; for (int i = 0; i < length; ++i) { int index = QRandomGenerator::global()->bounded(possibleCharacters.size()); randomString.append(possibleCharacters.at(index)); } qDebug() << "randomString request_id:" << randomString; return randomString; } QString HmacSha256ToBase64(const QString& data, const QString& secret) { QByteArray keyBytes = secret.toUtf8(); QByteArray dataBytes = data.toUtf8(); // 使用 HMAC-SHA256 计算哈希值 QByteArray hash = QMessageAuthenticationCode::hash(dataBytes, keyBytes, QCryptographicHash::Sha256); qDebug() << "secret:" << secret; qDebug() << "hash (hex):" << hash.toHex(); qDebug() << "hash.toBase64():" << hash.toHex().toBase64(); // 将哈希值编码为 Base64 字符串 return hash.toHex().toBase64(); } // 计算签名 QString calculateSignature(const QMap& params, const QString& httpMethod, const QString& secret, const QString& request_id, const QString& timestamp) { // 1. 按字典序排序参数 QList> sortedParams; for (auto it = params.begin(); it != params.end(); ++it) { qDebug() << it.key() << ":" << it.value(); sortedParams.append(qMakePair(it.key(), it.value())); } std::sort(sortedParams.begin(), sortedParams.end()); qDebug() << "Sorted Params:"; for (const auto& param : sortedParams) { qDebug() << param.first << ":" << param.second; } // 2. URL 编码参数 QString canonicalizedQueryString; for (auto& param : sortedParams) { if (!canonicalizedQueryString.isEmpty()) { canonicalizedQueryString += "&"; } canonicalizedQueryString += QUrl::toPercentEncoding(param.first) + "=" + QUrl::toPercentEncoding(param.second); } qDebug() << "URL Canonicalized Query String:" << canonicalizedQueryString; // 3. 构造 BaseString //QString baseString = params["batch"] + params["label"] + params["model"] + params["request_id"] + params["timestamp"] + params["factory_id"]; QString baseString = "240830SL100LabelSL100" + request_id + timestamp + "TEST"; qDebug() << "baseString:" << baseString; // 4. 构造 stringToSign QString stringToSign = httpMethod + "&" + baseString + "&" + canonicalizedQueryString.replace("+", "%20"); qDebug() << "stringToSign:" << stringToSign; // 5. 计算签名 return HmacSha256ToBase64(stringToSign, secret); } // 请求头 void prepareRequestHeaders(QNetworkRequest& request, const QString& sign, const QString& request_id) { request.setRawHeader("factory_id", "TEST"); request.setRawHeader("label", "SL100Label"); request.setRawHeader("batch", QString::number(240830).toUtf8()); request.setRawHeader("model", "SL100"); request.setRawHeader("timestamp", QString::number(QDateTime::currentSecsSinceEpoch()).toUtf8()); request.setRawHeader("request_id", request_id.toUtf8()); request.setRawHeader("sign", sign.toUtf8()); request.setRawHeader("Content-Type", "application/json"); } // GET 请求 void sendGetRequest(HttpClient* httpClient, const QUrl& url, const QMap& params, const QString& secret) { QString request_id = generateRandomRequestID(); qDebug() << "request_id:" << request_id; QUrl modifiedUrl = url; QUrlQuery query; for (auto it = params.begin(); it != params.end(); ++it) { query.addQueryItem(it.key(), it.value()); } modifiedUrl.setQuery(query.query()); QString sign = calculateSignature(params, "GET", secret, request_id, QString::number(QDateTime::currentSecsSinceEpoch())); qDebug() << "sendGetRequest URL:" << modifiedUrl.toString(); QNetworkRequest request(modifiedUrl); prepareRequestHeaders(request, sign, request_id); //return; httpClient->sendGetRequest(request); } // POST 请求 void sendPostRequest(HttpClient* httpClient, const QUrl& url, const QMap& params, const QJsonObject& jsonData, const QString& secret) { QString request_id = generateRandomRequestID(); qDebug() << "request_id:" << request_id; QString sign = calculateSignature(params, "POST", secret, request_id, QString::number(QDateTime::currentSecsSinceEpoch())); qDebug() << "sendPostRequest URL:" << url.toString(); QNetworkRequest request(url); prepareRequestHeaders(request, sign, request_id); QByteArray jsonDataByteArray = QJsonDocument(jsonData).toJson(); //return; httpClient->sendPostRequest(request, jsonDataByteArray); } // GET 获取 UUID void MainWidget::FactoryToolSendGetUuidToHttpServer() { QUrl url("http://admin.hassecurity.cn/v1/getUuid"); QMap params = { {"label", "TEST_SL100_20240826"}, {"model", "SL100"}, {"batch", "1"}, {"mac", "2a:61:az:a1"} }; QString secret = "rCeOzwisLFLasvlt"; sendGetRequest(httpClient, url, params, secret); } // GET 查询 License void MainWidget::FactoryToolSendGetLicenseToHttpServer(const QString& hw_info) { QUrl url("http://admin.hassecurity.cn/v1/getAlgorithmKey"); QMap params = { {"id", hw_info} }; QString secret = "rCeOzwisLFLasvlt"; sendGetRequest(httpClient, url, params, secret); } // POST 确认烧录 void MainWidget::FactoryToolSendPostComfirmToHttpServer() { QUrl url("http://admin.hassecurity.cn/v1/confirm"); QMap params = { {"factory_id", "TEST"}, {"label", "SL100Label"}, {"batch", "240830"}, {"model", "SL100"}, {"timestamp", QString::number(QDateTime::currentSecsSinceEpoch())}, {"request_id", generateRandomRequestID()} }; QJsonObject jsonData = { {"mac", "value4"}, {"uuid", "value4"} }; QString secret = "rCeOzwisLFLasvlt"; sendPostRequest(httpClient, url, params, jsonData, secret); } // POST 上报测试结果 void MainWidget::FactoryToolSendPostTestToHttpServer() { QUrl url("http://admin.hassecurity.cn/v1/testRecords"); QMap params = { {"id", "123456"}, {"location", "allMachine"} }; //QString itemString = "function=faceVerify,result=false,msg=timeout"; //QString itemString = "function=faceVerify,result=false,msg=timeout"; QString itemString = "[{\"function\":\"faceVerify\",\"msg\":\"timeout\",\"result\":false}]"; params["items"] = itemString; QJsonObject jsonItem = { {"function", "faceVerify"}, {"result", false}, {"msg", "timeout"} }; QJsonArray itemsArray; itemsArray.append(jsonItem); QJsonObject jsonData = { {"id", "123456"}, {"location", "allMachine"}, {"items", itemsArray} }; QString secret = "rCeOzwisLFLasvlt"; sendPostRequest(httpClient, url, params, jsonData, secret); } // POST 图语 License 上报 void MainWidget::FactoryToolSendPostLicenseToHttpServer(const QString& hardware_info, const QString& license_info) { QUrl url("http://admin.hassecurity.cn/v1/algorithmKey"); QString UTC_time = QString::number(QDateTime::currentSecsSinceEpoch()); QMap params = { {"id", hardware_info}, {"key", license_info}, {"time", UTC_time}, {"type", "TUYU"} }; QJsonObject jsonData = { {"id", hardware_info}, {"key", license_info}, {"time", UTC_time} }; QString secret = "rCeOzwisLFLasvlt"; sendPostRequest(httpClient, url, params, jsonData, secret); } void MainWidget::startClientReadTimer(int clientId) { qDebug() << "------ startClientReadTimer clientId:" << clientId; if (clientReadTimers.contains(clientId)) { clientReadTimers[clientId]->start(10); } } void MainWidget::stopClientReadTimer(int clientId) { qDebug() << "------ stopClientReadTimer clientId:" << clientId; if (clientReadTimers.contains(clientId)) { clientReadTimers[clientId]->stop(); } } void MainWidget::onCheckConnectionStatus() { int activeThreadCount = clients_1.size(); //qDebug() << "------Number of active threads:" << activeThreadCount; for (auto it = clients_1.begin(); it != clients_1.end(); ++it) { int clientId = it.key(); ClientHandler* handler = it.value(); QTcpSocket* socket = handler->getSocket(); if (socket->state() != QTcpSocket::ConnectedState) { qCritical() << "--------------Connection lost for clientId:" << clientId << ". Socket state:" << socket->state(); emit handler->clientDisconnected(handler); } else { qDebug() << "Connection for clientId:" << clientId << "is active."; } } } void MainWidget::onCheckThreadStatus() { //qDebug() << "Checking thread status..."; int activeThreadCount = clientThreads.size(); //qDebug() << "Number of active threads:" << activeThreadCount; for (auto it = clientThreads.begin(); it != clientThreads.end(); ++it) { int clientId = it.key(); QThread* thread = it.value(); ClientHandler* handler = nullptr; for (ClientHandler* h : clients) { if (h->getClientId() == clientId) { handler = h; break; } } if (handler && handler->isData_Stuck()) { qDebug() << "Thread for clientId:" << clientId << "is stuck."; // 处理线程卡住的情况,比如重启线程或记录更多日志 } else if (thread->isRunning()) { qDebug() << "isData_Stuck = :" << handler->isData_Stuck(); qDebug() << "Thread for clientId:" << clientId << "is running."; } else { qDebug() << "Thread for clientId:" << clientId << "is not running."; // 处理线程意外停止的情况 } } } // 打印线程池信息 void MainWidget::printThreadPoolInfo() { QThreadPool* threadPool = QThreadPool::globalInstance(); //qDebug() << "Active threads:" << threadPool->activeThreadCount(); //qDebug() << "Max threads:" << threadPool->maxThreadCount(); } void MainWidget::setupTimerForThreadPoolInfo() { QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWidget::printThreadPoolInfo); timer->start(5000); // 每5秒打印一次线程池信息 } void MainWidget::readJsonConfig() { frontBoardOneClickTest = readJson_frontBoardOneClickTest(); frontBoardTest = readJson_frontBoardTest(); frontBoardFuncConfig = readJson_frontBoardFuncConfig(); frontBoardDevInfoJson = readJson_frontDevInfo(); frontBoardLicenseJson = readJson_frontLicense(); backBoardOneClickTest = readJson_backBoardOneClickTest(); backBoardTest = readJson_backBoardTest(); backBoardFuncConfig = readJson_backBoardFuncConfig(); backBoardDevInfoJson = readJson_backDevInfo(); backBoardUuidJson = readJson_backUuid(); testJsonConfig = readJson_testConfig(); funcJsonConfig = readJson_funcConfig(); getPicJson = readJson_getPic(); getVideoJson = readJson_getVideo(); } // 设置 UI void MainWidget::setupUI() { startServerButton = new QPushButton("开始监听\n(Start Listening...)", this); startServerButton->setFixedSize(190, 70); sendAllButton = new QPushButton("一键功能测试", this); sendAllButton->setFixedSize(190, 70); sendAllButton->setEnabled(false); statusListWidget = new QListWidget(this); statusListWidget->setMinimumSize(350, 840); statusListWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QHBoxLayout* buttonLayout = new QHBoxLayout; buttonLayout->addWidget(startServerButton); buttonLayout->addWidget(sendAllButton); buttonLayout->addStretch(); QVBoxLayout* leftLayout = new QVBoxLayout; leftLayout->addLayout(buttonLayout); leftLayout->setStretch(0, 1); leftLayout->addWidget(statusListWidget); leftLayout->setStretch(1, 200); saveCheckBox = new QCheckBox("", this); selectFileButton = new QPushButton("Save", this); selectFileButton->setFixedSize(45, 28); clearLogButton = new QPushButton("Clear", this); clearLogButton->setFixedSize(55, 28); filePathLineEdit = new QLineEdit(this); filePathLineEdit->setFixedSize(250, 28); filePathLineEdit->setReadOnly(true); QHBoxLayout* fileLayout = new QHBoxLayout; fileLayout->addWidget(saveCheckBox); fileLayout->addWidget(selectFileButton); fileLayout->addWidget(filePathLineEdit); fileLayout->addWidget(clearLogButton); leftLayout->addLayout(fileLayout); leftLayout->setStretch(2, 1); // 读取 JSON 配置文件 readJsonConfig(); /*QGroupBox* groupBox = createLicenseGroupBox(); leftLayout->addWidget(groupBox); leftLayout->setStretch(3, 1);*/ QWidget* leftContainer = new QWidget(this); leftContainer->setLayout(leftLayout); leftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 前板 QGroupBox* frontDeviceInfoGroupBox = createFrontDeviceInfoGroupBox(); QGroupBox* frontLicenseGroupBox = createLicenseGroupBox(); QHBoxLayout* frontGroupBoxLayout = new QHBoxLayout; frontGroupBoxLayout->addWidget(frontDeviceInfoGroupBox, 1); frontGroupBoxLayout->addWidget(frontLicenseGroupBox, 1); QTabWidget* frontTabWidget = new QTabWidget(this); frontTabWidget->setFixedSize(900, 315); QWidget* frontFunctionTestTab = createFunctionTestTab(frontBoardTest, "frontBoardTest"); QWidget* frontFunctionConfigTab = createFunctionConfigTab(frontBoardFuncConfig, "frontBoardFuncConfig"); frontTabWidget->addTab(frontFunctionTestTab, "前板测试项"); frontTabWidget->addTab(frontFunctionConfigTab, "前板配置项"); QTabWidget* mainTabWidget = new QTabWidget(this); QWidget* frontDevAreaTab = new QWidget(this); QVBoxLayout* frontDevLayout = new QVBoxLayout(frontDevAreaTab); frontDevLayout->addLayout(frontGroupBoxLayout); frontDevLayout->addWidget(frontTabWidget, 2, Qt::AlignTop | Qt::AlignLeft); mainTabWidget->addTab(frontDevAreaTab, "前 板"); // 后板 QGroupBox* backDeviceInfoGroupBox1 = createBackDeviceInfoGroupBox(); QGroupBox* BackConnectServerGroupBox = createBackConnectServerGroupBox(); QHBoxLayout* backGroupBoxLayout = new QHBoxLayout; backGroupBoxLayout->addWidget(backDeviceInfoGroupBox1, 1); backGroupBoxLayout->addWidget(BackConnectServerGroupBox, 1); QTabWidget* backTabWidget = new QTabWidget(this); backTabWidget->setFixedSize(900, 315); QWidget* backFunctionTestTab = createFunctionTestTab(backBoardTest, "backBoardTest"); QWidget* backFunctionConfigTab = createFunctionConfigTab(backBoardFuncConfig, "backBoardFuncConfig"); backTabWidget->addTab(backFunctionTestTab, "后板测试项"); backTabWidget->addTab(backFunctionConfigTab, "后板配置项"); QWidget* backDevAreaTab = new QWidget(this); QVBoxLayout* backDevLayout = new QVBoxLayout(backDevAreaTab); backDevLayout->addLayout(backGroupBoxLayout); backDevLayout->addWidget(backTabWidget, 2, Qt::AlignTop | Qt::AlignLeft); mainTabWidget->addTab(backDevAreaTab, "后 板"); // 整机 QWidget* allDevAreaTab = new QWidget(this); QVBoxLayout* allDevLayout = new QVBoxLayout(allDevAreaTab); mainTabWidget->addTab(allDevAreaTab, "整 机"); QTabWidget* tabWidget_media = new QTabWidget(this); QWidget* imageDisplayTab = createImageDisplayTab(); QWidget* videoDisplayTab = createVideoDisplayTab(); tabWidget_media->addTab(imageDisplayTab, "图像显示区"); tabWidget_media->addTab(videoDisplayTab, "视频显示区"); QVBoxLayout* rightVerticalLayout = new QVBoxLayout; rightVerticalLayout->addWidget(mainTabWidget, 5); rightVerticalLayout->addWidget(tabWidget_media, 4); QHBoxLayout* mainLayout = new QHBoxLayout; mainLayout->addWidget(leftContainer, 1, Qt::AlignTop | Qt::AlignLeft); mainLayout->addLayout(rightVerticalLayout, 3); setLayout(mainLayout); setWindowTitle("SL100 工厂产测工具 - V0.0.1"); resize(1340, 1000); connect(startServerButton, &QPushButton::clicked, this, &MainWidget::onStartServerClicked); connect(sendAllButton, &QPushButton::clicked, this, &MainWidget::onSendAllClicked); connect(statusListWidget, &QListWidget::itemChanged, this, &MainWidget::scrollToBottom); connect(selectFileButton, &QPushButton::clicked, this, &MainWidget::onSelectFileButtonClicked); connect(clearLogButton, &QPushButton::clicked, this, &MainWidget::onclearLogButtonClicked); connect(saveCheckBox, &QCheckBox::stateChanged, this, &MainWidget::onSaveCheckBoxStateChanged); } void MainWidget::onSelectFileButtonClicked() { QString filePath = QFileDialog::getSaveFileName(this, tr("选择文件路径"), "", tr("Text Files (*.txt);;All Files (*)")); if (!filePath.isEmpty()) { filePathLineEdit->setText(filePath); } } void MainWidget::onclearLogButtonClicked() { statusListWidget->clear(); } void MainWidget::onSaveCheckBoxStateChanged(int state) { if (state == Qt::Checked) { saveStatusListToFile(filePathLineEdit->text()); } } void MainWidget::saveStatusListToFile(const QString& filePath) { if (filePath.isEmpty()) { return; } QFile file(filePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } QTextStream out(&file); for (int i = 0; i < statusListWidget->count(); ++i) { QListWidgetItem* item = statusListWidget->item(i); out << item->text() << "\n"; } file.close(); } void MainWidget::onStartTimeout(int clientId, int timeout) { //qDebug() << "---------------> onStartTimeout :" << clientId << "timeout :" << timeout; if (clientTimers.contains(clientId)) { QTimer* timer = clientTimers[clientId]; if (timeout > 0) { timer->start(timeout); } else { timer->stop(); } } } void MainWidget::scrollToBottom() { statusListWidget->scrollToBottom(); } void MainWidget::onDisconnectClient(int clientId) { for (ClientHandler* handler : clients) { if (handler->getClientId() == clientId) { // 断开与该客户端的连接 handler->getSocket()->disconnectFromHost(); handler->getSocket()->waitForDisconnected(); clients.removeOne(handler); if (clientTimers.contains(clientId)) { QTimer* timer = clientTimers[clientId]; timer->stop(); delete timer; clientTimers.remove(clientId); } handler->deleteLater(); connectedClientsCount--; updateServerButtonText(); break; } } // 启动 mDNS 服务广播 startMdnsService(); } // 处理客户端断开连接信号 void MainWidget::onClientDisconnected(ClientHandler* handler) { int clientId = handler->getClientId(); if (clientTimers.contains(clientId)) { QTimer* timer = clientTimers[clientId]; timer->stop(); delete timer; clientTimers.remove(clientId); } clients.removeOne(handler); /* 将 ClientHandler 对象的删除操作放入事件队列中,等待事件循环处理。 在事件循环执行时,会安全地删除 ClientHandler 对象,这包括释放其占用的资源和内存 */ handler->deleteLater(); // 延迟删除 ClientHandler 对象 // 更新连接数并更新按键文本 connectedClientsCount--; if (nextClientId <= 2) nextClientId--; deviceConnected = true; updateServerButtonText(); } // 更新按键文本的函数 void MainWidget::updateServerButtonText() { if (deviceConnected) { deviceConnected = false; startServerButton->setText(tr("正在监听(Listening)")); if (connectedClientsCount == 0) startMdnsService(); } else if (connectedClientsCount == 0) { startServerButton->setText(tr("开始监听\n(Start Listening...)")); } else { startServerButton->setText(tr("正在监听(Listening)\n%1 台设备连接").arg(connectedClientsCount)); } } QString formatLicenseKey(const QString& licenseKey) { QString formattedKey; qDebug() << "licenseKey.length():" << licenseKey.length(); for (int i = 0; i < licenseKey.length(); i += 2) { QString byteStr = licenseKey.mid(i, 2); // 每次取两个字符 formattedKey.append(QString("0x%1, ").arg(byteStr)); } if (!formattedKey.isEmpty()) { formattedKey.chop(2); } return formattedKey; } void MainWidget::onLicenseButtonClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); if (button) { int index = button->property("licenseIndex").toInt(); if (index >= 0 && index < frontBoardLicenseJson.size()) { QJsonObject jsonObject = frontBoardLicenseJson[index].toObject(); unsigned char hardware_info[PIX_HARDWARE_INFO_BYTES] = { 0 }; unsigned char license_info[PIX_LICENCE_BYTES] = { 0 }; QString dataStr = ""; if (jsonObject["lable"].toString() == "get_license") { QString hwInfoText = licenseHwInfoEdit->toPlainText(); dataStr = hwInfoText.remove(","); // 去掉所有的逗号 QString sendToHttpServerDataStr = dataStr.replace("0x", "").replace(" ", ""); // 去掉0x和空格 #if 1 qDebug() << "sendToHttpServerDataStr:" << sendToHttpServerDataStr; FactoryToolSendGetLicenseToHttpServer(sendToHttpServerDataStr); while (isRequestSuccessful == 0) { QCoreApplication::processEvents(); // 防止阻塞UI线程 } qDebug() << "isRequestSuccessful:" << isRequestSuccessful; if (isRequestSuccessful == 2) { return; } else if(isRequestSuccessful == 1) { if (licenseDataArray.contains("has") && licenseDataArray["has"].toBool()) { qDebug() << "Found item with 'has' = true"; if (licenseDataArray.contains("key")) { QString licenseKey = licenseDataArray["key"].toString(); licenseKey = formatLicenseKey(licenseKey); licenseHwInfoEdit->setPlainText(licenseKey); qDebug() << "HTTP Server License is:" << licenseKey; return; } } else if (licenseDataArray.contains("has")) { qDebug() << "licenseDataArray[\"has\"].toBool():" << licenseDataArray["has"].toBool(); } } #else QString licenseKey = "128532C1D2A8"; licenseKey = formatLicenseKey(licenseKey); licenseHwInfoEdit->setPlainText(licenseKey); qDebug() << "License Key set in licenseHwInfoEdit:" << licenseKey; return; #endif QByteArray dataByteArray = QByteArray::fromHex(dataStr.toUtf8()); memcpy(hardware_info, dataByteArray.data(), qMin(dataByteArray.size(), PIX_HARDWARE_INFO_BYTES)); //unsigned char hardware_info[PIX_HARDWARE_INFO_BYTES] = { 0x46,0x0b,0x5d,0x11,0x58,0x17,0x4d,0x5e,0x55,0x5c,0x51,0x4a,0x5a,0x07,0x59,0x4c,0x5f,0x45,0x5b,0x5f,0x5a,0x45,0x1c,0x5a,0x45,0x43,0x44,0x47,0x51,0x5e,0x44,0x30 }; LicenseConfirmWindow dialog("你确定要获取此授权吗?"); if (dialog.exec() == QDialog::Accepted) { #if 0 licenseGenerate(hardware_info, license_info); QString licenseInfoHex = QByteArray(reinterpret_cast(license_info), PIX_LICENCE_BYTES).toHex().toUpper(); #else unsigned char license_info_1[PIX_LICENCE_BYTES] = { 0x07, 0xe8, 0xf3, 0x80, 0xa8, 0x07, 0x72, 0xa1, 0x17, 0xfe, 0xda, 0x67, 0xbd, 0x4a, 0x5a, 0xb5, 0xbb, 0x8b, 0x2d, 0xb2, 0xbf, 0x89, 0x74, 0xe5, 0xb0, 0x99, 0x70, 0x74, 0x3c, 0x6f, 0xf8, 0x82, 0x79, 0xab, 0x31, 0x9c, 0xdf, 0xe8, 0x9e, 0x75, 0x8f, 0x42, 0xb3, 0xcf, 0x00, 0x60, 0xa0, 0x38, 0xa4, 0xb8, 0xbe, 0xa6, 0x5d, 0x9f, 0x8b, 0x41, 0xf3, 0x0a, 0x69, 0xf6, 0x50, 0x94, 0x3f, 0xd0, 0xa5, 0xee, 0x88, 0x20, 0x93, 0x9a, 0x1c, 0xe9, 0x64, 0xd3, 0xaf, 0x9f, 0xc7, 0x66, 0x00, 0x7d, 0x7d, 0x68, 0xf1, 0xa4, 0xe1, 0x58, 0x00, 0x1d, 0x03, 0x0d, 0x40, 0x08, 0xa4, 0xcc, 0x0b, 0xd8, 0x19, 0x70, 0x9a, 0x83, 0x81, 0xbf, 0x27, 0x35, 0xb8, 0xec, 0x59, 0xa8, 0xd0, 0x03, 0xdb, 0xf6, 0xcf, 0x83, 0xaa, 0x0e, 0xfc, 0x95, 0x29, 0x77, 0xec, 0x89, 0xc5, 0x79, 0x10, 0x40, 0xd8, 0xbb }; QString licenseInfoHex = QByteArray(reinterpret_cast(license_info_1), PIX_LICENCE_BYTES).toHex().toUpper(); #endif qDebug() << "上报服务器 licenseInfoHex:" << licenseInfoHex; // License上报服务器 FactoryToolSendPostLicenseToHttpServer(sendToHttpServerDataStr, licenseInfoHex); QString licenseInfoStr; printf("U盘 Get License is\n"); for (int j = 0; j < PIX_LICENCE_BYTES; ++j) { //printf("0x%02x, ", license_info[j]); //licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info[j])); printf("0x%02x, ", license_info_1[j]); licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info_1[j])); } printf("\n"); licenseHwInfoEdit->setPlainText(licenseInfoStr); } } else { #if 0 if (jsonObject["lable"].toString() == "write_license") { QString hwInfoText = licenseHwInfoEdit->toPlainText(); dataStr = hwInfoText.remove(","); // 去掉所有的逗号 QByteArray dataByteArray = QByteArray::fromHex(dataStr.toUtf8()); memcpy(hardware_info, dataByteArray.data(), qMin(dataByteArray.size(), PIX_HARDWARE_INFO_BYTES)); qDebug() << "hardware_info:" << QByteArray(reinterpret_cast(hardware_info), PIX_HARDWARE_INFO_BYTES).toHex(); licenseGenerate(hardware_info, license_info); QString licenseInfoStr; printf("License is\n"); for (int j = 0; j < PIX_LICENCE_BYTES; ++j) { printf("0x%02x, ", license_info[j]); licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info[j])); } printf("\n"); licenseHwInfoEdit->setPlainText(licenseInfoStr); dataStr = QByteArray(reinterpret_cast(license_info), PIX_LICENCE_BYTES).toHex(); qDebug() << "license_info:" << dataStr; } #else if (jsonObject["lable"].toString() == "write_license") { QString licenseInfoText = licenseHwInfoEdit->toPlainText(); qDebug() << "licenseInfoText:" << licenseInfoText; dataStr = licenseInfoText.remove(","); // 去掉所有的逗号 dataStr = dataStr.replace("0x", "").replace(" ", ""); // 去掉0x和空格 QByteArray dataByteArray = QByteArray::fromHex(dataStr.toUtf8()); memcpy(license_info, dataByteArray.data(), qMin(dataByteArray.size(), PIX_LICENCE_BYTES)); //qDebug() << "hardware_info:" << QByteArray(reinterpret_cast(hardware_info), PIX_HARDWARE_INFO_BYTES).toHex(); //licenseGenerate(hardware_info, license_info); QString licenseInfoStr; for (int j = 0; j < PIX_LICENCE_BYTES; ++j) { licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info[j])); } //printf("\n"); dataStr = QByteArray(reinterpret_cast(license_info), PIX_LICENCE_BYTES).toHex(); qDebug() << "license_info:" << dataStr; } #endif for (ClientHandler* handler : clients) { handler->sendLicenseItem(index, dataStr); } } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } //void MainWidget::onLicenseButtonClicked() //{ // if (connectedClientsCount) { // QPushButton* button = qobject_cast(sender()); // if (button) { // int index = button->property("licenseIndex").toInt(); // if (index >= 0 && index < frontBoardLicenseJson.size()) { // QJsonObject jsonObject = frontBoardLicenseJson[index].toObject(); // //QString jsonString = QJsonDocument(jsonObject).toJson(QJsonDocument::Compact); // //qDebug() << "license Button clicked, sending JSON:" << jsonString; // unsigned char license_info[PIX_LICENCE_BYTES] = { 0 }; // if (jsonObject["lable"].toString() == "get_license") { // LicenseConfirmWindow dialog("你确定要获取此授权吗?"); // if (dialog.exec() == QDialog::Accepted) // licenseGenerate(license_info, license_info); // } // else { // if (jsonObject["lable"].toString() == "write_license") { // LicenseConfirmWindow dialog("你确定要发送此授权吗?"); // if (dialog.exec() == QDialog::Accepted) // licenseGenerate(license_info, license_info); // } // for (ClientHandler* handler : clients) { // handler->sendLicenseItem(index); // } // } // } // } // } // else { // QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); // listItem->setBackground(Qt::red); // } //} void MainWidget::onUuidButtonClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); if (button) { int index = button->property("UuidIndex").toInt(); if (index >= 0 && index < backBoardUuidJson.size()) { QJsonObject jsonObject = backBoardUuidJson[index].toObject(); //QString jsonString = QJsonDocument(jsonObject).toJson(QJsonDocument::Compact); //qDebug() << "license Button clicked, sending JSON:" << jsonString; unsigned char license_info[PIX_LICENCE_BYTES] = { 0 }; if (jsonObject["lable"].toString() == "get_license") { } else { if (jsonObject["lable"].toString() == "write_license") { LicenseConfirmWindow dialog("你确定要发送此授权吗?"); if (dialog.exec() == QDialog::Accepted) licenseGenerate(license_info, license_info); } for (ClientHandler* handler : clients) { handler->sendUuidItem(index, ""); } } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::startMdnsService() { QDateTime currentTime = QDateTime::currentDateTime(); QString formattedTime = currentTime.toString("yyyy-MM-dd hh:mm:ss.zzz"); qDebug() << "[" << formattedTime << "]:" << "Start Mdns Broadcast Service"; QString serviceName = "SL100 FactoryTool Mdns Broadcast Service"; QString serviceType = "_SL100_FactoryTool-service._tcp"; quint16 port = TCP_CONNECT_PORT; mServiceProvider->startServiceBroadcast(serviceName, serviceType, port); if (!mdnsTimer->isActive()) { mdnsTimer->start(1000); } } void MainWidget::stopMdnsService() { if (mdnsTimer->isActive()) { mdnsTimer->stop(); // 停止定时器 } mServiceProvider->stopServiceBroadcast(); } #if TEST_UDP_BROADCAST void MainWidget::sendMulticastMessage() { QByteArray datagram = "--------------------------------- Test multicast message from MainWidget"; QHostAddress groupAddress("224.0.0.251"); quint16 port = 5353; qint64 sentBytes = multicastSocket->writeDatagram(datagram, groupAddress, port); if (sentBytes == -1) { qWarning() << "Failed to send multicast message:" << multicastSocket->errorString(); } else { qDebug() << "Multicast message sentBytes:" << sentBytes; qDebug() << "Multicast message sent:" << datagram; } } #endif // 处理开始服务器按键点击事件 void MainWidget::onStartServerClicked() { if (!server->isListening()) { startMdnsService(); #if TEST_UDP_BROADCAST sendMulticastMessage(); #endif // QHostAddress specifiedIpAddress("10.10.10.253"); quint16 specifiedPort = TCP_CONNECT_PORT; qDebug() << "" << specifiedPort; if (server->listen(QHostAddress::Any, specifiedPort)) { startServerButton->setText(tr("正在监听(Listening)")); startServerButton->setStyleSheet("background-color: green;"); sendAllButton->setEnabled(true); } else { qDebug() << "Failed to start server. Error:" << server->errorString(); } } else { server->close(); startServerButton->setText(tr("开始监听\n(Start Listening...)")); startServerButton->setStyleSheet(""); sendAllButton->setEnabled(false); stopMdnsService(); } } void MainWidget::sendDataToClient(int clientId, const QByteArray& data) { if (clients_1.contains(clientId)) { ClientHandler* handler = clients_1[clientId]; handler->sendDataToClient(data); // 调用 ClientHandler 中的方法发送数据 } else { qWarning() << "没有找到 ID 为" << clientId << "的客户端!"; } } // 处理发送获取设备信息按键点击事件 void MainWidget::onSendGetDevInfoClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("deviceInfoIndex").toInt(); if (itemIndex + 1 > connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("No device %1 is connected !!!").arg(itemIndex + 1), statusListWidget); listItem->setBackground(Qt::red); } else { for (ClientHandler* handler : clients) { handler->sendGetDevInfoItem(itemIndex); } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理发送取图按键点击事件 void MainWidget::onSendGetPicClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("getPicIndex").toInt(); if (itemIndex < 2) { button->setStyleSheet("background-color: green;"); if (lastClickedGetPicCamIndex != -1 && lastClickedGetPicCamIndex != itemIndex) { getPicButtons[lastClickedGetPicCamIndex]->setStyleSheet(""); } lastClickedGetPicCamIndex = itemIndex; } else { if (lastClickedGetPicCamIndex == -1) { QListWidgetItem* listItem = new QListWidgetItem(QString("Please select IR or RGB lens to get image!!!"), statusListWidget); listItem->setBackground(Qt::red); } else { if (itemIndex - 2 >= connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("No device %1 is connected !!!").arg(itemIndex - 1), statusListWidget); listItem->setBackground(Qt::red); } else { button->setStyleSheet("background-color: green;"); if (lastClickedGetPicDevIndex != -1 && lastClickedGetPicDevIndex != itemIndex) { getPicButtons[lastClickedGetPicDevIndex]->setStyleSheet(""); } lastClickedGetPicDevIndex = itemIndex; //QMutexLocker locker(&mutex); for (ClientHandler* handler : clients) { handler->sendGetPicItem(itemIndex - 2, lastClickedGetPicCamIndex); } } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理发送拉视频流按键点击事件 void MainWidget::onSendGetVideoClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("getVideoIndex").toInt(); if (itemIndex < 2) { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoCamIndex != -1 && lastClickedGetVideoCamIndex != itemIndex) { getVideoButtons[lastClickedGetVideoCamIndex]->setStyleSheet(""); } lastClickedGetVideoCamIndex = itemIndex; } else { if (lastClickedGetVideoCamIndex == -1) { QListWidgetItem* listItem = new QListWidgetItem(QString("Please select IR or RGB lens to get video!!!"), statusListWidget); listItem->setBackground(Qt::red); } else { if (itemIndex - 6 >= connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("No device %1 is connected !!!").arg(itemIndex - 4), statusListWidget); listItem->setBackground(Qt::red); } else { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoDevIndex != -1 && lastClickedGetVideoDevIndex != itemIndex) { getVideoButtons[lastClickedGetVideoDevIndex]->setStyleSheet(""); } lastClickedGetVideoDevIndex = itemIndex; //QMutexLocker locker(&mutex); for (ClientHandler* handler : clients) { handler->sendGetVideoItem(itemIndex - 5, 1); } getVideoButtons[2]->setEnabled(true); } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onOpenFocusWindowClicked() { QPushButton* button = qobject_cast(sender()); if (button) { int itemIndex = button->property("getVideoIndex").toInt(); //qDebug() << "New Button clicked with itemIndex:" << itemIndex; if (itemIndex == 2) { // 创建并显示新窗口 NewButtonDialog dialog(this); dialog.exec(); } } } // 处理一键发送按键点击事件 void MainWidget::onSendAllClicked() { if (connectedClientsCount) { QMutexLocker locker(&mutex); isSendingAll = !isSendingAll; if (isSendingAll) { sendAllButton->setText("一键功能测试中...\n再次点击取消"); sendAllButton->setStyleSheet("background-color: green;"); manualSend = true; for (ClientHandler* handler : clients) { // 重置索引 handler->resetCurrentItemIndex(); handler->sendNextItem(); //handler->sendDevInfoItem(); } } else { sendAllButton->setText("一键功能测试"); sendAllButton->setStyleSheet("background-color: white;"); manualSend = false; for (ClientHandler* handler : clients) { handler->resetCurrentItemIndex(); } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理单独发送功能项按键点击事件 void MainWidget::onSendFrontFuncItemClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("frontBoardFuncConfig").toInt(); for (ClientHandler* handler : clients) { QString text = frontFuncConfigLineEdit->text(); qDebug() << "Text in frontFuncConfigLineEdit:" << text; handler->sendFrontFuncItem(itemIndex, text); } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onSendBackFuncItemClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("backBoardFuncConfig").toInt(); for (ClientHandler* handler : clients) { QString text = backFuncConfigLineEdit->text(); qDebug() << "Text in backFuncConfigLineEdit:" << text; handler->sendBackFuncItem(itemIndex, text); } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理单独发送项按键点击事件 void MainWidget::onSendFrontItemClicked() { qDebug() << "onSendFrontItemClicked" ; if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("frontBoardTest").toInt(); for (ClientHandler* handler : clients) { handler->sendFrontItem(itemIndex); } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onSendBackItemClicked() { qDebug() << "onSendBackItemClicked"; if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("backBoardTest").toInt(); for (ClientHandler* handler : clients) { handler->sendBackItem(itemIndex); } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理状态更新信号 void MainWidget::onStatusUpdated(const QString& client, int itemIndex, int FuncItemIndex, bool success, const QString& itemData, const QString& funcItemData) { int clientId = -1; // 遍历所有的 ClientHandler,找到匹配的 client for (ClientHandler* handler : clients) { if (handler->getClientAddress() == client) { clientId = handler->getClientId(); QString lable = handler->getCurrentItemLable(); lable = handler->getCurrentFuncItemLable(); break; } else { //qDebug() << "" << __FUNCTION__ << "handler->getClientAddress() != client" ; } } //qDebug() << "itemIndex :" << itemIndex; //qDebug() << "FuncItemIndex:" << FuncItemIndex; if (itemIndex > 0) { QListWidgetItem* listItem = new QListWidgetItem(QString("device ID: %1 - Item %2: %3 ---> %4") .arg(clientId) .arg(itemIndex) .arg(itemData) // data 字段 .arg(success ? "OK" : "NG"), statusListWidget); listItem->setBackground(success ? Qt::green : Qt::red); statusListWidget->addItem(listItem); } else if (FuncItemIndex > 0) { QListWidgetItem* listItem = new QListWidgetItem(QString("device ID: %1 - funcItem %2: %3 ---> %4") .arg(clientId) .arg(FuncItemIndex) .arg(funcItemData) // data 字段 .arg(success ? "OK" : "NG"), statusListWidget); listItem->setBackground(success ? Qt::green : Qt::red); statusListWidget->addItem(listItem); } statusListWidget->scrollToBottom(); } // json文件里面的配置项都测试结束 void MainWidget::onAllItemsProcessed(const QString& client, int itemsProcessedCount) { isSendingAll = false; sendAllButton->setText("一键功能测试"); sendAllButton->setStyleSheet("background-color: white;"); //qDebug() << "onAllItemsProcessed called for client:" << client << "itemsProcessedCount:" << itemsProcessedCount; int clientId = -1; for (ClientHandler* handler : clients) { if (handler->getClientAddress() == client) { clientId = handler->getClientId(); qDebug() << "Current clientId:" << clientId; break; } else { //qDebug() << "" << __FUNCTION__ << "handler->getClientAddress() != client"; } } QListWidgetItem* listItem = new QListWidgetItem(QString("device ID:-%1 ---> All %2 items test completed !!!") .arg(clientId) .arg(itemsProcessedCount), statusListWidget); statusListWidget->addItem(listItem); statusListWidget->scrollToBottom(); }