1028 lines
41 KiB
C++
1028 lines
41 KiB
C++
// MainWidget.cpp
|
||
#include "MainWidget.h"
|
||
#include "../RecvDataHandler/RecvDataHandler.h"
|
||
#include "../Json/readJsonFile.h"
|
||
#include "../LicenseGenerate/LicenseGenerate.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)
|
||
{
|
||
leftLens_imageLabel = new QLabel(this);
|
||
rightLens_imageLabel = new QLabel(this);
|
||
videoLabel = new QLabel(this);
|
||
funcConfigLineEdit = new QLineEdit(this);
|
||
|
||
setupUI();
|
||
// 打印线程池状态信息
|
||
setupTimerForThreadPoolInfo();
|
||
server = new QTcpServer(this);
|
||
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() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
|
||
|
||
// 更新连接数量并更新按键文本
|
||
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, backBoardDevInfoJson,
|
||
getPicJson, getVideoJson, clientId, nullptr);
|
||
|
||
// 将 ClientHandler 移动到线程池中的线程
|
||
handler->moveToThread(thread);
|
||
|
||
// 当线程结束时删除 handler
|
||
//connect(thread, &QThread::finished, handler, &QObject::deleteLater);
|
||
//connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, this, [=]() {
|
||
onThreadFinished(thread, handler);
|
||
});
|
||
|
||
// 将sendData信号连接到主线程中的槽上
|
||
connect(handler, &ClientHandler::sendData, this, [socket](const QByteArray& data) {
|
||
socket->write(data);
|
||
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, 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;
|
||
}
|
||
});
|
||
|
||
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检查一次连接状态
|
||
}
|
||
|
||
MainWidget::~MainWidget() {
|
||
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::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秒打印一次线程池信息
|
||
}
|
||
|
||
// 设置 UI
|
||
void MainWidget::setupUI()
|
||
{
|
||
startServerButton = new QPushButton("开始监听\n(Start Listening...)", this);
|
||
startServerButton->setFixedSize(190, 70); // 设置宽度为 190 像素,高度为 70 像素
|
||
|
||
sendAllButton = new QPushButton("一键功能测试", this);
|
||
sendAllButton->setFixedSize(190, 70); // 设置宽度为 190 像素,高度为 70 像素
|
||
sendAllButton->setEnabled(false);
|
||
|
||
statusListWidget = new QListWidget(this);
|
||
//statusListWidget->setMinimumSize(350, 880);
|
||
statusListWidget->setMinimumSize(350, 680);
|
||
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 = new QGroupBox("算法 license", this);
|
||
QHBoxLayout* buttonRowLayout = new QHBoxLayout;
|
||
for (int i = 0; i < frontBoardLicenseJson.size(); ++i) {
|
||
QJsonObject item = frontBoardLicenseJson[i].toObject();
|
||
QString buttonText = item["lable"].toString();
|
||
QPushButton* button = new QPushButton(buttonText, this);
|
||
button->setProperty("licenseIndex", i);
|
||
buttonRowLayout->addWidget(button);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onLicenseButtonClicked);
|
||
}
|
||
QLineEdit* readOnlyLineEdit = new QLineEdit(this);
|
||
readOnlyLineEdit->setReadOnly(true);
|
||
readOnlyLineEdit->setText("This is a read-only text");
|
||
readOnlyLineEdit->setFixedHeight(80);
|
||
|
||
QVBoxLayout* groupBoxLayout_license = new QVBoxLayout;
|
||
groupBoxLayout_license->addLayout(buttonRowLayout);
|
||
groupBoxLayout_license->addWidget(readOnlyLineEdit);
|
||
groupBox->setLayout(groupBoxLayout_license);
|
||
|
||
leftLayout->addWidget(groupBox);
|
||
leftLayout->setStretch(3, 1);
|
||
|
||
QWidget* leftContainer = new QWidget(this);
|
||
leftContainer->setLayout(leftLayout);
|
||
leftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||
|
||
QTabWidget* tabWidget = new QTabWidget(this);
|
||
tabWidget->setFixedSize(900, 315); // 设置 QTabWidget 的固定大小
|
||
|
||
QGroupBox* frontDeviceInfoGroupBox = new QGroupBox("前板设备信息", this);
|
||
QVBoxLayout* frontDeviceInfoLayout = new QVBoxLayout(frontDeviceInfoGroupBox);
|
||
|
||
QVBoxLayout* frontDeviceLabelsLayout = new QVBoxLayout;
|
||
for (const QJsonValue& value : frontBoardDevInfoJson) {
|
||
QJsonObject item = value.toObject();
|
||
QString label = item["lable"].toString();
|
||
QLabel* itemLabel = new QLabel(label, this);
|
||
QLineEdit* itemLineEdit = new QLineEdit(this);
|
||
itemLineEdit->setReadOnly(true);
|
||
|
||
QHBoxLayout* itemLayout = new QHBoxLayout;
|
||
itemLayout->addWidget(itemLabel);
|
||
itemLayout->addWidget(itemLineEdit);
|
||
|
||
frontDeviceLabelsLayout->addLayout(itemLayout);
|
||
}
|
||
frontDeviceInfoLayout->addLayout(frontDeviceLabelsLayout);
|
||
frontDeviceInfoLayout->addStretch();
|
||
|
||
QGroupBox* backDeviceInfoGroupBox = new QGroupBox("后板设备信息", this);
|
||
QVBoxLayout* backDeviceInfoLayout = new QVBoxLayout(backDeviceInfoGroupBox);
|
||
|
||
QVBoxLayout* backDeviceLabelsLayout = new QVBoxLayout;
|
||
for (const QJsonValue& value : backBoardDevInfoJson) {
|
||
QJsonObject item = value.toObject();
|
||
QString label = item["lable"].toString();
|
||
QLabel* itemLabel = new QLabel(label, this);
|
||
QLineEdit* itemLineEdit = new QLineEdit(this);
|
||
itemLineEdit->setReadOnly(true);
|
||
|
||
QHBoxLayout* itemLayout = new QHBoxLayout;
|
||
itemLayout->addWidget(itemLabel);
|
||
itemLayout->addWidget(itemLineEdit);
|
||
|
||
backDeviceLabelsLayout->addLayout(itemLayout);
|
||
}
|
||
backDeviceInfoLayout->addLayout(backDeviceLabelsLayout);
|
||
backDeviceInfoLayout->addStretch();
|
||
|
||
QHBoxLayout* groupBoxLayout = new QHBoxLayout;
|
||
groupBoxLayout->addWidget(frontDeviceInfoGroupBox, 1);
|
||
groupBoxLayout->addWidget(backDeviceInfoGroupBox, 1);
|
||
|
||
QWidget* functionTestTab = new QWidget;
|
||
QVBoxLayout* functionTestLayout = new QVBoxLayout(functionTestTab);
|
||
functionTestTab->setLayout(functionTestLayout);
|
||
tabWidget->addTab(functionTestTab, "功能测试区");
|
||
|
||
QGridLayout* buttonGridLayout = new QGridLayout();
|
||
|
||
int buttonsPerRow = 7; // 每行显示的按键数量,根据需要调整
|
||
|
||
// 为每个 JSON 项目创建按键,并添加到 rightLayout
|
||
// 先总共放 77 个按键
|
||
//qDebug() << "testJsonConfig.size():" << testJsonConfig.size();
|
||
for (int i = 0; i < frontBoardTest.size() + (77 - frontBoardTest.size()); ++i) {
|
||
QJsonObject item = frontBoardTest[i].toObject();
|
||
QString buttonText = item["lable"].toString();
|
||
// 判断 buttonText 是否为空或者只有空白字符
|
||
if (buttonText.isEmpty()) {
|
||
//qDebug() << "buttonText.isEmpty():" << buttonText.isEmpty();
|
||
buttonText = QString("Send Item %1").arg(i + 1);
|
||
}
|
||
QPushButton* button = new QPushButton(buttonText, this);
|
||
button->setProperty("frontBoardTest", i);
|
||
button->setFixedSize(110, 35); // 设置按键宽度和高度
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendItemClicked);
|
||
|
||
int row = i / buttonsPerRow;
|
||
int col = i % buttonsPerRow;
|
||
buttonGridLayout->addWidget(button, row, col, Qt::AlignLeft);
|
||
|
||
itemButtons.append(button);
|
||
}
|
||
|
||
QWidget* buttonContainer = new QWidget;
|
||
buttonContainer->setLayout(buttonGridLayout);
|
||
|
||
QScrollArea* scrollArea = new QScrollArea;
|
||
scrollArea->setWidget(buttonContainer);
|
||
scrollArea->setWidgetResizable(true);
|
||
|
||
functionTestLayout->addWidget(scrollArea);
|
||
|
||
QWidget* functionConfigTab = new QWidget;
|
||
QVBoxLayout* functionConfigLayout = new QVBoxLayout(functionConfigTab);
|
||
functionConfigTab->setLayout(functionConfigLayout);
|
||
tabWidget->addTab(functionConfigTab, "功能配置区");
|
||
|
||
funcConfigLineEdit->setPlaceholderText("请输入配置参数...");
|
||
functionConfigLayout->addWidget(funcConfigLineEdit);
|
||
|
||
QGridLayout* configButtonGridLayout = new QGridLayout();
|
||
|
||
for (int i = 0; i < frontBoardFuncConfig.size() + (77 - frontBoardFuncConfig.size()); ++i) {
|
||
QJsonObject item = frontBoardFuncConfig[i].toObject();
|
||
QString buttonText = item["lable"].toString();
|
||
// 判断 buttonText 是否为空或者只有空白字符
|
||
if (buttonText.isEmpty()) {
|
||
//qDebug() << "buttonText.isEmpty():" << buttonText.isEmpty();
|
||
buttonText = QString("Cfg Item %1").arg(i + 1);
|
||
}
|
||
QPushButton* button = new QPushButton(buttonText, this);
|
||
button->setProperty("frontBoardFuncConfig", i);
|
||
button->setFixedSize(110, 35); // 设置按键宽度和高度
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendFuncItemClicked);
|
||
|
||
int row = i / buttonsPerRow;
|
||
int col = i % buttonsPerRow;
|
||
configButtonGridLayout->addWidget(button, row, col, Qt::AlignLeft);
|
||
|
||
funcItemButtons.append(button);
|
||
}
|
||
|
||
QWidget* configButtonContainer = new QWidget;
|
||
configButtonContainer->setLayout(configButtonGridLayout);
|
||
|
||
QScrollArea* configScrollArea = new QScrollArea;
|
||
configScrollArea->setWidget(configButtonContainer);
|
||
configScrollArea->setWidgetResizable(true);
|
||
|
||
functionConfigLayout->addWidget(configScrollArea);
|
||
|
||
QTabWidget* tabWidget_media = new QTabWidget(this);
|
||
QWidget* imageDisplayTab = new QWidget;
|
||
QVBoxLayout* imageDisplayLayout = new QVBoxLayout(imageDisplayTab);
|
||
imageDisplayTab->setLayout(imageDisplayLayout);
|
||
tabWidget_media->addTab(imageDisplayTab, "图像显示区");
|
||
|
||
QVBoxLayout* imageButtonsColumnLayout = new QVBoxLayout;
|
||
for (int i = 0; i < 5; ++i) {
|
||
QHBoxLayout* imageButtonsRowLayout = new QHBoxLayout;
|
||
for (int j = 0; j < 2; ++j) {
|
||
QPushButton* button;
|
||
if (i == 0 && j == 0) {
|
||
button = new QPushButton(QString("IR"), this);
|
||
button->setFixedSize(73, 50);
|
||
imageButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getPicIndex", i * 2 + j);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendGetPicClicked);
|
||
getPicButtons.append(button);
|
||
continue;
|
||
}
|
||
else if (i == 0 && j == 1) {
|
||
button = new QPushButton(QString("RGB"), this);
|
||
button->setFixedSize(73, 50);
|
||
imageButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getPicIndex", i * 2 + j);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendGetPicClicked);
|
||
getPicButtons.append(button);
|
||
continue;
|
||
}
|
||
|
||
button = new QPushButton(QString("Device %1").arg(i * 2 + j - 1), this);
|
||
button->setFixedSize(73, 50);
|
||
imageButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getPicIndex", i * 2 + j);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendGetPicClicked);
|
||
getPicButtons.append(button);
|
||
}
|
||
imageButtonsColumnLayout->addLayout(imageButtonsRowLayout);
|
||
}
|
||
|
||
QHBoxLayout* lensesLayout = new QHBoxLayout;
|
||
leftLens_imageLabel = new QLabel(this);
|
||
rightLens_imageLabel = new QLabel(this);
|
||
lensesLayout->addWidget(leftLens_imageLabel);
|
||
lensesLayout->addWidget(rightLens_imageLabel);
|
||
|
||
QHBoxLayout* imageAndButtonsLayout = new QHBoxLayout;
|
||
imageAndButtonsLayout->addLayout(imageButtonsColumnLayout, 1);
|
||
imageAndButtonsLayout->addLayout(lensesLayout, 4);
|
||
imageDisplayLayout->addLayout(imageAndButtonsLayout);
|
||
|
||
QWidget* videoDisplayTab = new QWidget;
|
||
QVBoxLayout* videoDisplayLayout = new QVBoxLayout(videoDisplayTab);
|
||
videoDisplayTab->setLayout(videoDisplayLayout);
|
||
tabWidget_media->addTab(videoDisplayTab, "视频显示区");
|
||
|
||
QVBoxLayout* videoButtonsColumnLayout = new QVBoxLayout;
|
||
for (int i = 0; i < 6; ++i) {
|
||
QHBoxLayout* videoButtonsRowLayout = new QHBoxLayout;
|
||
for (int j = 0; j < 2; ++j) {
|
||
QPushButton* button;
|
||
if (i == 0 && j == 0) {
|
||
button = new QPushButton(QString("IR"), this);
|
||
button->setFixedSize(73, 50);
|
||
videoButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getVideoIndex", i * 2 + j);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendGetVideoClicked);
|
||
getVideoButtons.append(button);
|
||
continue;
|
||
}
|
||
else if (i == 0 && j == 1) {
|
||
button = new QPushButton(QString("RGB"), this);
|
||
button->setFixedSize(73, 50);
|
||
videoButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getVideoIndex", i * 2 + j);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendGetVideoClicked);
|
||
getVideoButtons.append(button);
|
||
continue;
|
||
}
|
||
|
||
// 调价调焦窗口按键
|
||
if (i == 1 && j == 0) {
|
||
button = new QPushButton(QString("大窗口播放视频"), this);
|
||
button->setFixedSize(150, 50);
|
||
button->setEnabled(false);
|
||
videoButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getVideoIndex", i * 2 + j);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onOpenFocusWindowClicked);
|
||
getVideoButtons.append(button);
|
||
break; // 跳出内层循环,只添加一个按键
|
||
}
|
||
|
||
//int adjustedIndex = (i > 1) ? i * 2 + j - 1 : i * 2 + j;
|
||
button = new QPushButton(QString("Device %1").arg(i * 2 + j - 3), this);
|
||
//button = new QPushButton(QString("Device %1").arg(adjustedIndex), this);
|
||
button->setFixedSize(73, 50);
|
||
videoButtonsRowLayout->addWidget(button);
|
||
button->setProperty("getVideoIndex", i * 2 + j + 1);
|
||
//button->setProperty("getVideoIndex", adjustedIndex);
|
||
connect(button, &QPushButton::clicked, this, &MainWidget::onSendGetVideoClicked);
|
||
getVideoButtons.append(button);
|
||
}
|
||
videoButtonsColumnLayout->addLayout(videoButtonsRowLayout);
|
||
}
|
||
|
||
QHBoxLayout* videoAndButtonsLayout = new QHBoxLayout;
|
||
videoLabel = new QLabel(this);
|
||
//videoLabel->setFixedSize(640, 480);
|
||
videoAndButtonsLayout->addLayout(videoButtonsColumnLayout, 1);
|
||
videoAndButtonsLayout->addWidget(videoLabel, 6);
|
||
videoDisplayLayout->addLayout(videoAndButtonsLayout);
|
||
|
||
QVBoxLayout* rightVerticalLayout = new QVBoxLayout;
|
||
rightVerticalLayout->addLayout(groupBoxLayout, 2);
|
||
rightVerticalLayout->addWidget(tabWidget, 2, Qt::AlignTop | Qt::AlignLeft);
|
||
rightVerticalLayout->addWidget(tabWidget_media, 5);
|
||
|
||
QHBoxLayout* mainLayout = new QHBoxLayout;
|
||
// 参数二:伸缩因子,leftContainer:1/3 ,rightLayout:2/3
|
||
mainLayout->addWidget(leftContainer, 1, Qt::AlignTop | Qt::AlignLeft); // 设置 leftContainer 左上对齐
|
||
mainLayout->addLayout(rightVerticalLayout, 3);
|
||
|
||
setLayout(mainLayout);
|
||
setWindowTitle("SL100 工厂产测工具 - V0.0.1");
|
||
resize(1340, 1000); // 设置宽度为 1440 像素,高度为 900 像素
|
||
|
||
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::readJsonConfig()
|
||
{
|
||
frontBoardOneClickTest = readJson_frontBoardOneClickTest();
|
||
frontBoardTest = readJson_frontBoardTest();
|
||
frontBoardFuncConfig = readJson_frontBoardFuncConfig();
|
||
frontBoardDevInfoJson = readJson_frontDevInfo();
|
||
frontBoardLicenseJson = readJson_frontLicense();
|
||
backBoardDevInfoJson = readJson_backDevInfo();
|
||
testJsonConfig = readJson_testConfig();
|
||
funcJsonConfig = readJson_funcConfig();
|
||
|
||
getPicJson = readJson_getPic();
|
||
getVideoJson = readJson_getVideo();
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理客户端断开连接信号
|
||
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)"));
|
||
}
|
||
else if (connectedClientsCount == 0) {
|
||
startServerButton->setText(tr("开始监听\n(Start Listening...)"));
|
||
}
|
||
else {
|
||
startServerButton->setText(tr("正在监听(Listening)\n%1 台设备连接").arg(connectedClientsCount));
|
||
}
|
||
}
|
||
|
||
// 处理 License 按键点击事件
|
||
void MainWidget::onLicenseButtonClicked()
|
||
{
|
||
if (connectedClientsCount) {
|
||
QPushButton* button = qobject_cast<QPushButton*>(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;
|
||
for (ClientHandler* handler : clients) {
|
||
handler->sendLicenseItem(index);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget);
|
||
listItem->setBackground(Qt::red);
|
||
}
|
||
}
|
||
|
||
// 处理开始服务器按键点击事件
|
||
void MainWidget::onStartServerClicked()
|
||
{
|
||
if (!server->isListening()) {
|
||
// 根据需要修改
|
||
//QHostAddress specifiedIpAddress("10.10.10.253");
|
||
quint16 specifiedPort = 12412;
|
||
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);
|
||
}
|
||
}
|
||
|
||
// 处理发送获取设备信息按键点击事件
|
||
void MainWidget::onSendGetDevInfoClicked()
|
||
{
|
||
if (connectedClientsCount) {
|
||
QPushButton* button = qobject_cast<QPushButton*>(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<QPushButton*>(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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget);
|
||
listItem->setBackground(Qt::red);
|
||
}
|
||
}
|
||
|
||
// 处理发送拉视频流按键点击事件
|
||
void MainWidget::onSendGetVideoClicked()
|
||
{
|
||
if (connectedClientsCount) {
|
||
QPushButton* button = qobject_cast<QPushButton*>(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 - 5 >= 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<QPushButton*>(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::onPowerOnSend()
|
||
//{
|
||
//
|
||
//}
|
||
|
||
// 处理一键发送按键点击事件
|
||
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();
|
||
//licenseGenerate();
|
||
}
|
||
}
|
||
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::onSendFuncItemClicked()
|
||
{
|
||
if (connectedClientsCount) {
|
||
QPushButton* button = qobject_cast<QPushButton*>(sender());
|
||
int itemIndex = button->property("frontBoardFuncConfig").toInt();
|
||
for (ClientHandler* handler : clients) {
|
||
QString text = funcConfigLineEdit->text();
|
||
qDebug() << "Text in funcConfigLineEdit:" << text;
|
||
handler->sendFuncItem(itemIndex, text);
|
||
}
|
||
}
|
||
else {
|
||
QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget);
|
||
listItem->setBackground(Qt::red);
|
||
}
|
||
}
|
||
|
||
// 处理单独发送项按键点击事件
|
||
void MainWidget::onSendItemClicked()
|
||
{
|
||
if (connectedClientsCount) {
|
||
QPushButton* button = qobject_cast<QPushButton*>(sender());
|
||
int itemIndex = button->property("frontBoardTest").toInt();
|
||
for (ClientHandler* handler : clients) {
|
||
handler->sendItem(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();
|
||
}
|
||
|