diff --git a/AUTH_USAGE_GUIDE.md b/AUTH_USAGE_GUIDE.md new file mode 100644 index 0000000..9ac14de --- /dev/null +++ b/AUTH_USAGE_GUIDE.md @@ -0,0 +1,198 @@ +# 认证系统使用文档 + +## 概述 + +这是一个完整的用户认证和管理系统,具有以下特性: +- 基于哈希的安全密码存储 +- JSON文件持久化用户数据 +- 现代化的Qt对话框界面 +- 组件化架构设计 +- 向后兼容的全局API + +## 主要组件 + +### 1. UserDataManager 类 +用户数据管理的核心类,负责: +- 用户的增删改查 +- 密码哈希和验证 +- JSON数据持久化 +- 认证对话框管理 + +### 2. AuthDialog 组件 +现代化的认证对话框,特性: +- 深色主题设计 +- 密码显示/隐藏切换 +- 回车键快捷操作 +- 用户友好的错误提示 + +### 3. Auth 命名空间 +提供全局便捷函数,保持向后兼容性 + +## 基本使用方法 + +### 1. 简单认证 + +```cpp +#include "src/launcher/GUI/front/auth.hpp" + +// 方法1:使用全局便捷函数 +UserDataManager::authResult result = Auth::authenticate(parentWidget); + +switch(result) { + case UserDataManager::OK: + // 认证成功 + break; + case UserDataManager::WrongPassword: + // 密码错误 + break; + case UserDataManager::UserNotFound: + // 用户不存在 + break; + case UserDataManager::Cancelled: + // 用户取消 + break; +} +``` + +### 2. 带回调的认证 + +```cpp +auto callback = []() -> bool { + // 认证成功后执行的操作 + return true; // 返回false会导致CallBackRunFalse结果 +}; + +UserDataManager::authResult result = Auth::authenticateWithCallback(callback, parentWidget); +``` + +### 3. 直接使用UserDataManager + +```cpp +// 创建用户管理器实例 +UserDataManager manager("./config/password.json"); + +// 添加用户 +bool success = manager.addUser("username", "password"); + +// 验证密码 +bool valid = manager.verifyPassword("username", "password"); + +// 获取所有用户 +auto users = manager.getAllUsers(); + +// 删除用户 +bool deleted = manager.deleteUser("username"); +``` + +## 高级功能 + +### 用户管理 + +```cpp +// 获取默认管理器实例 +UserDataManager& manager = Auth::getDefaultManager(); + +// 检查用户是否存在 +bool exists = manager.userExists("username"); + +// 修改密码 +bool changed = manager.changePassword("username", "oldpass", "newpass"); + +// 获取用户信息 +auto userInfo = manager.getUserInfo("username"); +if (userInfo.has_value()) { + std::cout << "用户名: " << userInfo->username << std::endl; + std::cout << "创建时间: " << userInfo->created_at << std::endl; + std::cout << "最后登录: " << userInfo->last_login << std::endl; +} +``` + +### 自定义认证对话框 + +```cpp +UserDataManager manager("./custom/path/users.json"); +UserDataManager::AuthDialog dialog(&manager, parentWidget); + +// 设置自定义标题 +dialog.setWindowTitle("自定义认证"); + +// 执行对话框 +int result = dialog.exec(); +if (result == QDialog::Accepted) { + auto authResult = dialog.getLastAuthResult(); + // 处理认证结果 +} +``` + +## 配置文件格式 + +用户数据以JSON格式存储在指定路径(默认:`./config/password.json`): + +```json +{ + "users": [ + { + "username": "admin", + "password_hash": "abc123...", + "salt": "xyz789...", + "created_at": "2024-01-01 12:00:00", + "last_login": "2024-01-15 09:30:00" + } + ] +} +``` + +## 安全特性 + +1. **密码哈希**:使用std::hash配合随机盐值 +2. **安全存储**:密码永不以明文形式存储 +3. **时间戳追踪**:记录用户创建和最后登录时间 +4. **文件权限**:自动创建配置目录和文件 + +## 错误处理 + +所有认证操作都返回详细的状态码: + +- `OK`:操作成功 +- `WrongPassword`:密码错误 +- `UserNotFound`:用户不存在 +- `Cancelled`:用户取消操作 +- `CallBackRunFalse`:认证成功但回调失败 + +## 最佳实践 + +1. **使用全局函数**:对于简单认证,推荐使用Auth命名空间的便捷函数 +2. **错误处理**:始终检查认证结果并提供适当的用户反馈 +3. **安全考虑**:定期备份用户数据文件 +4. **性能优化**:重复使用UserDataManager实例而非频繁创建 + +## 迁移指南 + +如果您之前使用的是旧版本的authDialog静态函数: + +```cpp +// 旧版本 +authResult result = authDialog::authenticate(parent); + +// 新版本(向后兼容) +UserDataManager::authResult result = Auth::authenticate(parent); +``` + +系统完全向后兼容,您可以逐步迁移到新的API。 + +## 编译要求 + +- Qt 5.12+ 或 Qt 6.x +- C++17标准 +- nlohmannJson.hpp 和 generalJsonParsing.hpp 头文件 + +## 故障排除 + +1. **编译错误**:确保包含了所有必需的头文件 +2. **文件权限**:确保应用程序有权限读写配置目录 +3. **JSON错误**:检查配置文件格式是否正确 +4. **认证失败**:检查用户名和密码是否正确 + +## 示例项目 + +参考 `auth_test_example.cpp` 获取完整的使用示例。 diff --git a/auth_test_example.cpp b/auth_test_example.cpp new file mode 100644 index 0000000..f4aeaf2 --- /dev/null +++ b/auth_test_example.cpp @@ -0,0 +1,133 @@ +// 认证系统使用示例和测试 +#include +#include +#include +#include +#include +#include "src/launcher/GUI/front/auth.hpp" + +class TestWidget : public QWidget { + Q_OBJECT + +public: + TestWidget(QWidget* parent = nullptr) : QWidget(parent) { + setupUI(); + connectSignals(); + } + +private slots: + void testBasicAuth() { + // 使用全局便捷函数进行基本认证 + UserDataManager::authResult result = Auth::authenticate(this); + + QString message; + switch(result) { + case UserDataManager::OK: + message = "认证成功!"; + break; + case UserDataManager::WrongPassword: + message = "密码错误!"; + break; + case UserDataManager::UserNotFound: + message = "用户不存在!"; + break; + case UserDataManager::Cancelled: + message = "用户取消了认证!"; + break; + default: + message = "未知错误!"; + } + + QMessageBox::information(this, "认证结果", message); + } + + void testAuthWithCallback() { + // 使用带回调的认证 + auto callback = []() -> bool { + // 这里可以执行任何需要认证后的操作 + QMessageBox::information(nullptr, "回调", "认证成功后的回调函数被执行!"); + return true; // 返回true表示回调成功 + }; + + UserDataManager::authResult result = Auth::authenticateWithCallback(callback, this); + + QString message; + switch(result) { + case UserDataManager::OK: + message = "认证和回调都成功!"; + break; + case UserDataManager::CallBackRunFalse: + message = "认证成功但回调失败!"; + break; + case UserDataManager::WrongPassword: + message = "密码错误!"; + break; + case UserDataManager::UserNotFound: + message = "用户不存在!"; + break; + case UserDataManager::Cancelled: + message = "用户取消了认证!"; + break; + default: + message = "未知错误!"; + } + + QMessageBox::information(this, "认证结果", message); + } + + void testUserManagement() { + // 获取用户管理器实例 + UserDataManager& manager = Auth::getDefaultManager(); + + // 添加测试用户 + bool success = manager.addUser("testuser", "testpass"); + if (success) { + QMessageBox::information(this, "用户管理", "测试用户添加成功!\n用户名: testuser\n密码: testpass"); + } else { + QMessageBox::warning(this, "用户管理", "测试用户添加失败!可能用户已存在。"); + } + + // 显示所有用户 + auto users = manager.getAllUsers(); + QString userList = "当前用户列表:\n"; + for (const auto& user : users) { + userList += QString::fromStdString(user.username) + "\n"; + } + QMessageBox::information(this, "用户列表", userList); + } + +private: + void setupUI() { + setWindowTitle("认证系统测试"); + setFixedSize(300, 200); + + auto* layout = new QVBoxLayout(this); + + auto* basicAuthBtn = new QPushButton("测试基本认证", this); + auto* callbackAuthBtn = new QPushButton("测试带回调认证", this); + auto* userMgmtBtn = new QPushButton("测试用户管理", this); + + layout->addWidget(basicAuthBtn); + layout->addWidget(callbackAuthBtn); + layout->addWidget(userMgmtBtn); + + connect(basicAuthBtn, &QPushButton::clicked, this, &TestWidget::testBasicAuth); + connect(callbackAuthBtn, &QPushButton::clicked, this, &TestWidget::testAuthWithCallback); + connect(userMgmtBtn, &QPushButton::clicked, this, &TestWidget::testUserManagement); + } + + void connectSignals() { + // 信号连接已在setupUI中完成 + } +}; + +int main(int argc, char *argv[]) { + QApplication app(argc, argv); + + TestWidget widget; + widget.show(); + + return app.exec(); +} + +#include "auth_test_example.moc" diff --git a/configSettingWidget.h b/configSettingWidget.h new file mode 100644 index 0000000..7baaa40 --- /dev/null +++ b/configSettingWidget.h @@ -0,0 +1,394 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "git_version.h" +#include +#include +#include +#include + +class configSettingWidget :public QWidget{ + Q_OBJECT +public: + + QVBoxLayout* m_layout; + QScrollArea* scrollArea; + QWidget* contentWidget; + QHBoxLayout* btnLayout; + std::vectorbtns; + QLabel* icon, * Title; + int currentPageIndex = 0; + configSettingWidget(appConfig* _configIn):_config(_configIn){ + QPalette palette; + palette.setColor(QPalette::WindowText, Qt::white); + QFont font("微软雅黑", 24, QFont::Bold); + QFont font2("微软雅黑", 8, QFont::Bold); + + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + this->setObjectName("configSettingWidget"); + this->setStyleSheet(R"( + QWidget#configSettingWidget { + background: rgb(40, 45, 50); + } + )"); + + // 创建主布局 + QVBoxLayout* mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + + // 创建滚动区域 + scrollArea = new QScrollArea(); + scrollArea->setObjectName("configScrollArea"); + scrollArea->setStyleSheet(R"( + QScrollArea#configScrollArea { + border: none; + background: transparent; + } + QScrollBar:vertical { + background: rgb(60, 65, 70); + width: 12px; + border-radius: 6px; + } + QScrollBar::handle:vertical { + background: rgb(100, 105, 110); + border-radius: 6px; + min-height: 20px; + } + QScrollBar::handle:vertical:hover { + background: rgb(120, 125, 130); + } + )"); + scrollArea->setWidgetResizable(true); + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + // 创建内容容器 + contentWidget = new QWidget(); + contentWidget->setObjectName("contentWidget"); + contentWidget->setStyleSheet("QWidget#contentWidget { background: transparent; }"); + + m_layout = new QVBoxLayout(contentWidget); + m_layout->setContentsMargins(20, 20, 20, 20); + m_layout->setSpacing(15); + m_layout->setAlignment(Qt::AlignLeft|Qt::AlignTop); + + // 创建标题区域容器 + QWidget* titleWidget = new QWidget(); + titleWidget->setObjectName("titleWidget"); + titleWidget->setStyleSheet(R"( + QWidget#titleWidget { + background: rgb(50, 55, 60); + border-radius: 10px; + padding: 15px; + } + )"); + + QVBoxLayout* titleContainerLayout = new QVBoxLayout(titleWidget); + titleContainerLayout->setContentsMargins(15, 15, 15, 15); + titleContainerLayout->setSpacing(10); + + // 主标题和版本信息布局 + QHBoxLayout* titleLayout = new QHBoxLayout(); + titleLayout->setContentsMargins(0, 0, 0, 0); + + Title = new QLabel(QString::fromStdString(_config->_translation.translate("Setting"))); + Title->setFont(font); + Title->setPalette(palette); + Title->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + + QLabel* versionShow = new QLabel(QString(u8"当前版本: v%1 | 提交版本: %2").arg(QString::fromStdString(softwareVersion)).arg(GIT_COMMIT_HASH)); + versionShow->setFont(font2); + versionShow->setPalette(palette); + versionShow->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + versionShow->setStyleSheet("color: rgb(180, 180, 180);"); + + titleLayout->addWidget(Title); + titleLayout->addStretch(); + titleLayout->addWidget(versionShow); + + titleContainerLayout->addLayout(titleLayout); + m_layout->addWidget(titleWidget); + //语言设置 + { + // 创建语言设置分组容器 + QGroupBox* languageGroupBox = new QGroupBox(QString::fromStdString(_config->_translation.translate("Language Settings"))); + languageGroupBox->setObjectName("languageGroupBox"); + languageGroupBox->setStyleSheet(R"( + QGroupBox#languageGroupBox { + background: rgb(50, 55, 60); + border-radius: 10px; + font-family: "微软雅黑"; + font-size: 14px; + font-weight: bold; + color: white; + padding-top: 20px; + } + QGroupBox#languageGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 10px 0 10px; + } + )"); + + QVBoxLayout* languageMainLayout = new QVBoxLayout(languageGroupBox); + languageMainLayout->setContentsMargins(15, 15, 15, 15); + languageMainLayout->setSpacing(10); + + QHBoxLayout* languageSelectLayout = new QHBoxLayout(); + languageSelectLayout->setSpacing(15); + + QLabel* languageSelectLabel = new QLabel(u8"选择语言/Language/Bahasa:"); + languageSelectLabel->setFont(font2); + languageSelectLabel->setPalette(palette); + languageSelectLabel->setMinimumWidth(200); + + QComboBox* languageSelect = new QComboBox(); + languageSelect->setMinimumWidth(150); + languageSelect->setStyleSheet(R"( + QComboBox { + background-color: rgb(70, 75, 80); + border: 2px solid rgb(100, 105, 110); + border-radius: 5px; + padding: 5px; + color: white; + font-family: "微软雅黑"; + font-size: 12px; + } + QComboBox:hover { + border-color: rgb(120, 125, 130); + } + QComboBox::drop-down { + border: none; + } + QComboBox::down-arrow { + image: url(:/icons/down-arrow.png); + } + )"); + + auto languagesKeys = _configIn->_translation.getSections(); + int index = 0; + for (int i = 0; i < languagesKeys.size(); i++) { + languageSelect->addItem(QString::fromStdString(languagesKeys[i])); + if (languagesKeys[i] == _configIn->_translation.getCurrentLanguage()) + index = i; + } + languageSelect->setCurrentIndex(index); + + QLabel* languageSelectTip = new QLabel(); + languageSelectTip->setFont(font2); + languageSelectTip->setPalette(palette); + languageSelectTip->setStyleSheet("color: rgb(255, 200, 100);"); + + languageSelectLayout->addWidget(languageSelectLabel); + languageSelectLayout->addWidget(languageSelect); + languageSelectLayout->addStretch(); + languageSelectLayout->addWidget(languageSelectTip); + + languageMainLayout->addLayout(languageSelectLayout); + + connect(languageSelect, &QComboBox::currentTextChanged, [=](const QString& str) { + _configIn->_translation.setLanguage(str.toStdString()); + languageSelectTip->setText(QString::fromStdString(_config->_translation.translate("will change after restart"))); + }); + + m_layout->addWidget(languageGroupBox); + } + //控制台 + { + // 创建控制台设置分组容器 + QGroupBox* consoleGroupBox = new QGroupBox(QString::fromStdString(_config->_translation.translate("Window Settings"))); + consoleGroupBox->setObjectName("consoleGroupBox"); + consoleGroupBox->setStyleSheet(R"( + QGroupBox#consoleGroupBox { + background: rgb(50, 55, 60); + border-radius: 10px; + font-family: "微软雅黑"; + font-size: 14px; + font-weight: bold; + color: white; + padding-top: 20px; + } + QGroupBox#consoleGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 10px 0 10px; + } + )"); + + QVBoxLayout* consoleMainLayout = new QVBoxLayout(consoleGroupBox); + consoleMainLayout->setContentsMargins(15, 15, 15, 15); + consoleMainLayout->setSpacing(10); + + // 添加说明文字 + QLabel* consoleDescription = new QLabel(QString::fromStdString(_config->_translation.translate("Control the visibility of the debug console window"))); + consoleDescription->setFont(font2); + consoleDescription->setPalette(palette); + consoleDescription->setStyleSheet("color: rgb(180, 180, 180);"); + consoleMainLayout->addWidget(consoleDescription); + + QHBoxLayout* consoletLayout = new QHBoxLayout(); + consoletLayout->setSpacing(15); + + fancyButtonText* showConsoleBtn = new fancyButtonText(QString::fromStdString(_config->_translation.translate("showConsole")), 120, 35, ""); + showConsoleBtn->setStyleSheet(R"( + fancyButtonText { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(80, 180, 80), stop:1 rgb(60, 140, 60)); + border-radius: 8px; + color: white; + font-weight: bold; + } + fancyButtonText:hover { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(100, 200, 100), stop:1 rgb(80, 160, 80)); + } + )"); + + fancyButtonText* hideConsoleBtn = new fancyButtonText(QString::fromStdString(_config->_translation.translate("hideConsole")), 120, 35, ""); + hideConsoleBtn->setStyleSheet(R"( + fancyButtonText { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(180, 80, 80), stop:1 rgb(140, 60, 60)); + border-radius: 8px; + color: white; + font-weight: bold; + } + fancyButtonText:hover { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(200, 100, 100), stop:1 rgb(160, 80, 80)); + } + )"); + + fancyButtonText* setResolutionBtn = new fancyButtonText( u8"设置1920x1040"); + setResolutionBtn->setStyleSheet(R"( + fancyButtonText { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(80, 130, 180), stop:1 rgb(60, 100, 140)); + border-radius: 8px; + color: white; + font-weight: bold; + } + fancyButtonText:hover { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(100, 150, 200), stop:1 rgb(80, 120, 160)); + } + )"); + + consoletLayout->addWidget(showConsoleBtn); + consoletLayout->addWidget(hideConsoleBtn); + consoletLayout->addWidget(setResolutionBtn); + consoletLayout->addStretch(); + + consoleMainLayout->addLayout(consoletLayout); + + connect(showConsoleBtn, &QPushButton::clicked, [=]() { + ShowWindow(_config->consoleHandle, SW_SHOW); + }); + + connect(hideConsoleBtn, &QPushButton::clicked, [=]() { + ShowWindow(_config->consoleHandle, SW_HIDE); + }); + + connect(setResolutionBtn, &QPushButton::clicked, [=]() { + // 获取当前窗口的顶级窗口 + QWidget* topWidget = this; + while (topWidget->parentWidget()) { + topWidget = topWidget->parentWidget(); + } + + // 设置窗口大小为1920x1080 + topWidget->resize(1920, 1080); + + // 可选:将窗口居中显示 + QScreen* screen = QApplication::primaryScreen(); + if (screen) { + QRect screenGeometry = screen->geometry(); + int x = (screenGeometry.width() - 1920) / 2; + int y = (screenGeometry.height() - 1080) / 2; + if (x >= 0 && y >= 0) { + topWidget->move(x, y); + } + } + }); m_layout->addWidget(consoleGroupBox); + } + // 硬件信息区域 + { + // 创建硬件信息分组容器 + QGroupBox* hardwareGroupBox = new QGroupBox(QString::fromStdString(_config->_translation.translate("Hardware Information"))); + hardwareGroupBox->setObjectName("hardwareGroupBox"); + hardwareGroupBox->setStyleSheet(R"( + QGroupBox#hardwareGroupBox { + background: rgb(50, 55, 60); + border-radius: 10px; + font-family: "微软雅黑"; + font-size: 14px; + font-weight: bold; + color: white; + padding-top: 20px; + } + QGroupBox#hardwareGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 10px 0 10px; + } + )"); + + QVBoxLayout* hardwareMainLayout = new QVBoxLayout(hardwareGroupBox); + hardwareMainLayout->setContentsMargins(15, 15, 15, 15); + hardwareMainLayout->setSpacing(10); + + // 设置硬件信息组件的样式 + _hardwareInfoWidget.setStyleSheet(R"( + QWidget { + background: transparent; + color: white; + font-family: "微软雅黑"; + } + QLabel { + color: rgb(220, 220, 220); + font-size: 12px; + } + )"); + + hardwareMainLayout->addWidget(&_hardwareInfoWidget); + m_layout->addWidget(hardwareGroupBox); + } + + // 添加底部伸缩空间 + m_layout->addStretch(); + + // 设置滚动区域 + scrollArea->setWidget(contentWidget); + mainLayout->addWidget(scrollArea); + + } +protected: + +private: + appConfig* _config; + hardwareInfoWidget _hardwareInfoWidget; + //std::vector> privateJsondatas;//路径与数据 + //std::vector> privateWidgets;//路径与数据 + //std::vectorjsonLayouts; +}; +#pragma once \ No newline at end of file diff --git a/eui_581.zip b/eui_581.zip deleted file mode 100644 index 8f33274..0000000 Binary files a/eui_581.zip and /dev/null differ diff --git a/include/simpleTools/windowsHardwareCtrl.hpp b/include/simpleTools/windowsCtrl.hpp similarity index 72% rename from include/simpleTools/windowsHardwareCtrl.hpp rename to include/simpleTools/windowsCtrl.hpp index 9022b5c..409b05e 100644 --- a/include/simpleTools/windowsHardwareCtrl.hpp +++ b/include/simpleTools/windowsCtrl.hpp @@ -97,4 +97,47 @@ static void EnableComPort(const char* portName) { // Cleanup SetupDiDestroyDeviceInfoList(hDevInfo); } +static bool isRunAsAdmin() { + BOOL fIsRunAsAdmin = FALSE; + PSID pAdministratorsGroup = NULL; + + // Allocate and initialize a SID of the administrators group. + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) + { + return false; + } + + // Determine whether the SID of administrators group is enabled in the primary access token of the process. + if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) + { + fIsRunAsAdmin = FALSE; + } + + // Free the allocated SID. + if (pAdministratorsGroup) + { + FreeSid(pAdministratorsGroup); + } + + return fIsRunAsAdmin; +} +static void restartAsAdmin() { + TCHAR szPath[MAX_PATH]; + if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) { + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.lpVerb = TEXT("runas"); + sei.lpFile = szPath; + sei.hwnd = NULL; + sei.nShow = SW_NORMAL; + + if (!ShellExecuteEx(&sei)) { + DWORD dwError = GetLastError(); + if (dwError == ERROR_CANCELLED) { + //std::cout << "The user refused to allow privileges elevation.\n"; + } + } + } +} #pragma once \ No newline at end of file diff --git a/include/yhGlobal.h b/include/yhGlobal.h index 0f205ae..0038184 100644 --- a/include/yhGlobal.h +++ b/include/yhGlobal.h @@ -2,6 +2,25 @@ #include #include #include + +#pragma region 基础函数 +#define CATCH_EXCEPTIONS \ + catch (HDevEngineCpp::HDevEngineException& ex) { \ + std::cout << "HDevEngineException: " << ex.Message() << std::endl; \ + qDebug() << "HDevEngineException: " << ex.Message(); \ + } \ + catch (HalconCpp::HException& ex) { \ + std::cout << "Halcon Exception Caught!" << std::endl; \ + std::cout << "Error Code: " << ex.ErrorCode() << std::endl; \ + std::cout << "Error Message: " << ex.ErrorMessage() << std::endl; \ + qDebug() << "Halcon Exception Caught!"; \ + qDebug() << "Error Code: " << ex.ErrorCode(); \ + qDebug() << "Error Message: " << ex.ErrorMessage(); \ + } \ + catch (const std::exception& e) { \ + std::cout << "Caught exception: " << e.what() << std::endl; \ + qDebug() << "Caught exception: " << e.what(); \ + } struct yh_581_address { int triggerAddr = -1; int snAddr = -1; @@ -26,59 +45,64 @@ static std::map generateYh581AddressMap(int startAddr, int } return result; } -struct _581_Result { - bool result = true; -}; + class detParams { public: }; -static _581_Result generalAlgoTest(std::shared_ptr data, detParams* _detParams) { - _581_Result _result; - qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; +#pragma endregion + +//算法回调函数需要包含完整的算法流程以及发送信号,发送ui图表,捕获异常,处理异常等操作 +//并且注意 异常可能会导致运行不到发送信号的函数,请在处理异常时发送异常结果 +static bool generalAlgoTest(std::shared_ptr data, detParams* _detParams, yh_581_address address) { + try { + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + std::vector < std::string> defects = {"测试"}; + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() < 1) + { + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[0].copyTo(Paint); + cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); + return false; + } - ///////////////////取图//处理////////////////// - if (data->oriImgs.size() != 1) - { - qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); - return _581_Result(); - } - if (data->oriImgs[0].rows == 100) { cv::Mat Paint; - data->oriImgs[0].copyTo(Paint); - cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); - return _581_Result(); + QMutex paintMutex; + clock_t start, finish; + start = clock(); + + cv::Mat src1 = data->oriImgs[0]; + + if (src1.channels() != 3) + cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); + else + src1.copyTo(Paint); + cv::putText(Paint, "pos:" + data->additional["触发地址"].toString().toStdString(), cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0), 2); + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + data->service->_missionResultHandle->handleAllResult(data->SNcode, !defects.size() > 0, defects);//发送图标操作 + data->resultImgs.push_back(Paint); + return true; } - - cv::Mat Paint; - QMutex paintMutex; - clock_t start, finish; - start = clock(); - - cv::Mat src1 = data->oriImgs[0]; - - if (src1.channels() != 3) - cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); - else - src1.copyTo(Paint); - cv::putText(Paint, "pos:" + data->additional["触发地址"].toString().toStdString(), cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0), 2); - data->resultImgs.push_back(Paint); - - return _result; + CATCH_EXCEPTIONS + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送异常结果 + return false; } -template -//使用此类必须对应以下逻辑 -//接受到触发信号后立即发送完成信号 -//在触发信号清零后复位完成信号 -class _581_Dgh_triggerTemplate { -public: +template +//此类适用于单相机多触发地址需要联合判断的情况的情况 比如顶盖焊,包膜,入壳机台 +//例触发地址有4个,输入信号为 1 0 0 1 则触发1和4的地址拍照检测,2和3拍照取图并废弃 +class _581_Union_triggerTemplate { +public: paramTemplte _detParams; - detCallbackChain* generalDet; + detCallbackChain* generalDet; std::string cameraName; QString viewerName; std::mapaddress; - using resultHandleCallback = std::function)>; /// /// 初始化 /// @@ -94,17 +118,19 @@ public: /// void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount,int oneTriggerCaptrueTimes, paramTemplte& detParamsIn, ServiceManager* _serviceManagerIn, qtFuncBridge* bridgeIn, - typename detCallbackChain::processAlgoCallback _processAlgoCallback, - resultHandleCallback resultCallbackIN){ + typename detCallbackChain::processAlgoCallback _processAlgoCallback, + QString saveObjectNameIN = "") { viewerName = viewerNameIN; cameraName = cameraNameIn; _serviceManager = _serviceManagerIn; _detParams = detParamsIn; bridge = bridgeIn; - resultCallback = resultCallbackIN; - generalDet = new detCallbackChain(_serviceManager, &_detParams, bridge); + + saveObjectName = saveObjectNameIN; + generalDet = new detCallbackChain(_serviceManager, &_detParams, bridge); generalDet->registerProcessAlgoCallback(_processAlgoCallback); address = generateYh581AddressMap(startAddr, triggerCount); + //联合触发器条件 std::vector> conditions; for (int i = 0; i < triggerCount; i++) { conditions.push_back(std::make_pair(address[i].triggerAddr, 1)); @@ -112,8 +138,8 @@ public: _serviceManager->_triggerManager->registerCallback(address[i].triggerAddr, 0, [this, i](int triggerPos, int triggerValue, QByteArray& byteArray) {_serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_0"); }, "D" + address[0].completeAddr.toStdString() + "清零"); } - _serviceManager->_triggerManager->registerUnionCallback(conditions, triggerManager::conditionMode::or ,[this](std::vector> vals, QByteArray& byteArray) - { + //注册联合触发器 任意触发地址置1时触发 + _serviceManager->_triggerManager->registerUnionCallback(conditions, triggerManager::conditionMode::or ,[this](std::vector> vals, QByteArray& byteArray){ int cnt = 0; for (auto& val : vals) { if (val.second == 1) @@ -123,23 +149,19 @@ public: cnt++; } }, ""); - generalDet->registerResultHandleCallback( - [this](std::shared_ptr data, const resultTemplate& r) { - int ch = data->additional["电池偏移"].toInt(); - resultCallback(address[ch], r, data); - }); } //获取图片并进行检测 void evaluate(int batteryOffset, QByteArray& byteArray) { _serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_1");//完成信号 固定只发在第0位 std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, false, -1); auto camera = _serviceManager->_cameraManager->getCamera(cameraName); + camera->clearCache(); std::shared_ptr data = _serviceManager->_detDataManager->createDetData( QString::number(address[batteryOffset].triggerAddr), sn, 1, camera->config.oriSaveFormat);//创建数据包 camera->captureImage(data);//拍照 - generalDet->ansyncProcess(data, "");//处理算法 + data->saveObjectName = saveObjectName; + generalDet->ansyncProcess(data, address[batteryOffset]);//处理算法 data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图")); - data->additional["电池偏移"] = batteryOffset; } //获取图片然后废弃 void captrueAndDiscard() { @@ -148,11 +170,75 @@ public: camera->captureImage(data);//拍照 _serviceManager->_detDataManager->deleteDetData(data->uuid); } - void resultHandle(yh_581_address address, const resultTemplate& result, std::shared_ptr data) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - } private: - resultHandleCallback resultCallback; + QString saveObjectName = ""; qtFuncBridge* bridge; ServiceManager* _serviceManager = nullptr; }; + +template +//此类适用于单相机多触发地址单次判断的情况,比如密封钉,三协机台 +//例触发地址有4个,输入信号为 1 0 0 1 则按顺序触发1和4的地址拍照检测,2和3不做处理 +class _581_Single_triggerTemplate { +public: + paramTemplte2 _detParams; + detCallbackChain* generalDet; + std::string cameraName; + QString viewerName; + std::mapaddress; + /// + /// 初始化 + /// + /// 相机名 + /// 窗口名 + /// 开始地址 + /// 触发信号数 + /// 单次触发调用几次相机模块 + /// 参数输入 + /// 默认 + /// 默认 + /// 算法函数 + /// + void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount, int oneTriggerCaptrueTimes, + paramTemplte2& detParamsIn, ServiceManager* _serviceManagerIn, qtFuncBridge* bridgeIn, + typename detCallbackChain::processAlgoCallback _processAlgoCallback, + QString saveObjectNameIN = "") { + viewerName = viewerNameIN; + cameraName = cameraNameIn; + _serviceManager = _serviceManagerIn; + _detParams = detParamsIn; + bridge = bridgeIn; + + saveObjectName = saveObjectNameIN; + generalDet = new detCallbackChain(_serviceManager, &_detParams, bridge); + generalDet->registerProcessAlgoCallback(_processAlgoCallback); + address = generateYh581AddressMap(startAddr, triggerCount); + //单次触发器条件 + for (int i = 0; i < triggerCount; i++) { + //注册单触发器 触发地址置1时触发 + _serviceManager->_triggerManager->registerCallback(address[i].triggerAddr, 0, [this, i](int triggerPos, int triggerValue, QByteArray& byteArray) { + evaluate(i, byteArray);}, ""); + //注册清除完成信号触发器 任意触发地址归零时触发一次 + _serviceManager->_triggerManager->registerCallback(address[i].triggerAddr, 0, [this, i](int triggerPos, int triggerValue, QByteArray& byteArray) { + _serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_0"); }, "D" + address[0].completeAddr.toStdString() + "清零"); + } + + } + //获取图片并进行检测 + void evaluate(int batteryOffset, QByteArray& byteArray) { + _serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_1");//完成信号 固定只发在第0位 + std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, false, -1); + auto camera = _serviceManager->_cameraManager->getCamera(cameraName); + camera->clearCache(); + std::shared_ptr data = _serviceManager->_detDataManager->createDetData( + QString::number(address[batteryOffset].triggerAddr), sn, 1, camera->config.oriSaveFormat);//创建数据包 + camera->captureImage(data);//拍照 + data->saveObjectName = saveObjectName; + generalDet->ansyncProcess(data, address[batteryOffset]);//处理算法 + data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图")); + } +private: + QString saveObjectName = ""; + qtFuncBridge* bridge; + ServiceManager* _serviceManager = nullptr; +}; \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..8fb6cfc --- /dev/null +++ b/readme.txt @@ -0,0 +1,3 @@ +展图时,如果图像的长宽超过5000像素时会被压缩一半,直到长宽不超过5000 +3D相机连接示例 +算法回调函数需要包含完整的算法流程以及发送信号,发送ui图表等操作 \ No newline at end of file diff --git a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp index 1fe1ee9..08e03a8 100644 --- a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp +++ b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp @@ -51,7 +51,16 @@ rpc_finsTcp::rpc_finsTcp() bool m_IsFinsTcp = false; rpc_finsTcp::~rpc_finsTcp() { - + if (subThread) { + subThread->quit(); + subThread->wait(); + delete subThread; + subThread = nullptr; + } + if (write_JsonRpcClient) { + delete write_JsonRpcClient; + write_JsonRpcClient = nullptr; + } qDebug() << " ~rpc_finsTcp success!"; } QQueue readDataQueue; diff --git a/src/Core/back/cameraManager.h b/src/Core/back/cameraManager.h index 222f225..bf88870 100644 --- a/src/Core/back/cameraManager.h +++ b/src/Core/back/cameraManager.h @@ -89,23 +89,33 @@ public: } qDebug() << __FUNCTION__ << " line:" << __LINE__ << "camera_mat size:" << mats.size(); } - void setDigitalShift(float value){ - readData("DigitalShift_" + std::to_string(value)); + inline void setDigitalShift(float value){ + writeData("DigitalShift_" + std::to_string(value)); } - void setExposureTime(float value){ - readData("exposure_" + std::to_string(value)); + inline void setExposureTime(float value){ + writeData("exposure_" + std::to_string(value)); } - void setUserSet(int value){ - readData("userset_" + std::to_string(value)); + inline void setUserSet(int value){ + writeData("userset_" + std::to_string(value)); + } + inline void clearCache() { + writeData("clearCache"); } private: qtFuncBridge* bridge; - void readData(std::string str) - { - QByteArray task_name(QByteArray::fromStdString(str)); + QByteArray readData(const std::string& str){ + QByteArray byteArray(QByteArray::fromStdString(str)); std::vector camera_mat; - if (!config.module_ptr->readData(camera_mat, task_name)) - qCritical() << "[Error] " << "set exposure error!"; + if (!config.module_ptr->readData(camera_mat, byteArray)) + qCritical() << "[Error] " << "module readdata error!cameraname"< camera_mat; + if (!config.module_ptr->writeData(camera_mat, byteArray)) + qCritical() << "[Error] " << "module readdata error!cameraname" << cameraName; + return byteArray; } int index = 0; int timeout = 5000; diff --git a/src/Core/back/detData.h b/src/Core/back/detData.h index 9f01da0..6e314f3 100644 --- a/src/Core/back/detData.h +++ b/src/Core/back/detData.h @@ -16,8 +16,7 @@ enum saveMode { class camera; class detData; class detDataManager; -class triggerManager; -using resultHandleCallback = std::function)>; +class ServiceManager; using algoEvaluateCallback = std::function,handleAiModelManager*)>; class detData{ public: @@ -46,7 +45,7 @@ public: QString uuid = getUuid();//根据时间和随机数生成的值,唯一 std::string SNcode;//SN条码 std::string cameraKeyName;//相机名 - triggerManager* triggerPtr = nullptr;//触发器指针 一般为plc模块指针 + ServiceManager* service;//服务类 包含plc交互模块,图标交互模块等 #pragma endregion #pragma region 存图相关 saveMode _saveMode = saveMode::basic; @@ -90,7 +89,6 @@ public: dataPtr->cameraKeyName = IN_cameraKeyName.toStdString(); dataPtr->imgSaveNameParameter.push_back(IN_cameraKeyName.toStdString()); dataPtr->oriFormat = oriFormat; - dataPtr->triggerPtr; dataPtr->SNcode = IN_SN; dataPtr->imgAmountMin = imgAmountMin; dataPtr->dManager = this; diff --git a/src/Core/back/triggerManager.h b/src/Core/back/triggerManager.h index 777393a..f464fbb 100644 --- a/src/Core/back/triggerManager.h +++ b/src/Core/back/triggerManager.h @@ -221,6 +221,7 @@ public: std::map> triggerCallbackFuncs; //单条件的触发器注册 bool registerCallback(int triggerAddress, int triggerValue, triggerCallback func, std::string funcName =""){ + QMutexLocker locer(&mutex); triggerCallbackStruct _triggerCallbackStruct; _triggerCallbackStruct.triggerAddress = triggerAddress; _triggerCallbackStruct.triggerValue = triggerValue; @@ -240,6 +241,7 @@ public: bool registerUnionCallback(std::vector> triggerAddressAndValue, conditionMode mode, uniontriggerCallback func, std::string funcName = "") { + QMutexLocker locer(&mutex); if (triggerAddressAndValue.size() < 2) { qCritical() << "联合触发器至少需要两个条件"; return false; @@ -269,7 +271,8 @@ public: qInfo() << "注册联合触发器成功:" << ownerStruct->readAllCmd << ", 条件数=" << unionTriggerCallbackFuncs[ownerStruct->readAllCmd].back().triggerAddressAndValue.size(); return true; } - void checkCallback(readAllStruct& _struct,QByteArray & byteArray){//检查是否符合回调函数的触发条件 + void checkCallback(readAllStruct _struct,QByteArray & byteArray){//检查是否符合回调函数的触发条件 + QMutexLocker locer(&mutex); for (auto callback : triggerCallbackFuncs[_struct.readAllCmd]) { if (checkTrigger(callback.triggerAddress, callback.triggerValue, _struct, byteArray) == true) @@ -287,6 +290,7 @@ public: } } void checkUnionCallback(readAllStruct& _struct, QByteArray& byteArray) { + QMutexLocker locer(&mutex); auto it = unionTriggerCallbackFuncs.find(_struct.readAllCmd); if (it == unionTriggerCallbackFuncs.end()) return; auto& vec = it->second; diff --git a/src/core/back/detCallbackChain.hpp b/src/core/back/detCallbackChain.hpp index 4a86627..69722a2 100644 --- a/src/core/back/detCallbackChain.hpp +++ b/src/core/back/detCallbackChain.hpp @@ -10,39 +10,35 @@ #include using namespace std::placeholders; -template +template class detCallbackChain { public: enum class State { Idle, algoEvaluate, resultHandle, Finished }; - using resultHandleCallback = std::function, resultTemplate)>; - using processAlgoCallback = std::function, handleAiModelsTemplate*)>; + using processAlgoCallback = std::function, handleAiModelsTemplate*, addressTemplate)>; detCallbackChain(ServiceManager* _ServiceManagerIn, handleAiModelsTemplate* _handleAiModelsTemplateIn, qtFuncBridge* bridgeIn) : _imgSaveThreadManager(_ServiceManagerIn->_imgSaveThreadManager), _handleAiModels(_handleAiModelsTemplateIn), _triggerManager(_ServiceManagerIn->_triggerManager), bridge(bridgeIn){ - + _serviceManager = _ServiceManagerIn; int threadCount = 2 * QThread::idealThreadCount(); QThreadPool::globalInstance()->setMaxThreadCount(threadCount); } - void ansyncProcess(std::shared_ptr data, QByteArray afterTakeImgCmd = "") { - QFuture future = QtConcurrent::run([this, data, afterTakeImgCmd]() { - process(data, afterTakeImgCmd); + //异步启动检测 + void ansyncProcess(std::shared_ptr data, addressTemplate address = addressTemplate()) { + QFuture future = QtConcurrent::run([this, data, address]() { + process(data, address); }); } - void process(std::shared_ptr data, QByteArray afterTakeImgCmd = "") { - + //启动检测 + void process(std::shared_ptr data, addressTemplate address = addressTemplate()) { + data->service = _serviceManager; while (data->oriImgs.size() < data->imgAmountMin) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - if(afterTakeImgCmd != "") - _triggerManager->writeShort(afterTakeImgCmd); //发送拍照完成指令 //等待图片满足要求后,储存原图,异步执行算法函数 - - auto resultData = algoEvaluate(data, _handleAiModels); - //执行完毕后异步获取储存使用结果 - resultHandle(data, resultData); + auto resultData = algoEvaluate(data, _handleAiModels, address); // 确保线程安全退出 qDebug() << "Processing finished for data with UUID:" << data->uuid; if (data->resultImgs.size() > 0) { @@ -57,50 +53,26 @@ public: else data->resultImgs[i].copyTo(pack.img); emit bridge->displayWidget_sendImg(pack); - } - + } } QThread::currentThread()->quit(); } - resultTemplate algoEvaluate(std::shared_ptr data, handleAiModelsTemplate* model) { - resultTemplate result; - try { - std::chrono::steady_clock::time_point algoStartTime = std::chrono::steady_clock::now(); - result = _processAlgoCallback(data, model); - std::chrono::steady_clock::time_point algoEndTime = std::chrono::steady_clock::now(); - data->algoTime = std::chrono::duration_cast(algoEndTime - algoStartTime).count(); - } - catch (HDevEngineCpp::HDevEngineException& ex) { - std::cout << "HDevEngineException: " << ex.Message() << std::endl; - qDebug() << "HDevEngineException: " << ex.Message(); - } - catch (HalconCpp::HException& ex) { - // 捕获Halcon异常 - std::cout << "Halcon Exception Caught!" << std::endl; - std::cout << "Error Code: " << ex.ErrorCode() << std::endl; - std::cout << "Error Message: " << ex.ErrorMessage() << std::endl; - - qDebug() << "Halcon Exception Caught!"; - qDebug() << "Error Code: " << ex.ErrorCode(); - qDebug() << "Error Message: " << ex.ErrorMessage(); - } - catch (const std::exception& e) - { - std::cout << "Caught exception: " << e.what() << std::endl; - qDebug() << "Caught exception: " << e.what(); - } + bool algoEvaluate(std::shared_ptr data, handleAiModelsTemplate* model, addressTemplate address = addressTemplate()) { + std::chrono::steady_clock::time_point algoStartTime = std::chrono::steady_clock::now(); + bool result = _processAlgoCallback(data, model, address); + std::chrono::steady_clock::time_point algoEndTime = std::chrono::steady_clock::now(); + data->algoTime = std::chrono::duration_cast(algoEndTime - algoStartTime).count(); + return result; } - void resultHandle(std::shared_ptr data, resultTemplate& resultdata){ + void resultHandle(std::shared_ptr data){ std::shared_ptr dataPtr = data; detDataManager* dManager = data->dManager; data->dManager->deleteDetData(data->uuid); try { detectionResultHandle(data); - for (auto func : resultHandleCallbacks) - func(data, resultdata); } catch (const std::exception& e) { @@ -132,9 +104,6 @@ public: void registerProcessAlgoCallback(processAlgoCallback func) { _processAlgoCallback = func; } - void registerResultHandleCallback(resultHandleCallback func) { - resultHandleCallbacks.push_back(func); - } #pragma endregion @@ -143,9 +112,8 @@ private: imgSaveThreadManager* _imgSaveThreadManager = nullptr; handleAiModelsTemplate* _handleAiModels = nullptr; triggerManager* _triggerManager = nullptr; - std::vector< resultHandleCallback>resultHandleCallbacks; processAlgoCallback _processAlgoCallback; - qtFuncBridge* bridge; - ServiceManager* _serviceManager; + qtFuncBridge* bridge = nullptr; + ServiceManager* _serviceManager = nullptr; }; #pragma once \ No newline at end of file diff --git a/src/core/back/missionResultHandle.h b/src/core/back/missionResultHandle.h index 6120548..78cde9e 100644 --- a/src/core/back/missionResultHandle.h +++ b/src/core/back/missionResultHandle.h @@ -6,7 +6,7 @@ public: missionResultHandle(qtFuncBridge* qtBridgeIn) { qtBridge = qtBridgeIn; } - //如果需要根据条码判断一个料的okng,则在此函数内完成判断 + //如果需要根据条码判断一个料的okng,只需要调用此函数即可 void handleAllResult(std::string SN,bool isNG,std::vector defectAndNum) { if (isNG == false) { qtBridge->pieWidgetAddOK(); diff --git a/src/launcher/GUI/JsonEditorDialog.h b/src/launcher/GUI/JsonEditorDialog.h index a525b76..a270e8c 100644 --- a/src/launcher/GUI/JsonEditorDialog.h +++ b/src/launcher/GUI/JsonEditorDialog.h @@ -8,16 +8,33 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include class JsonParamTableEditor : public QDialog { Q_OBJECT + + // 定义JSON类型枚举 + enum class JsonValueType { + String, + Number, + Boolean, + Array, + Object, + Null + }; + public: explicit JsonParamTableEditor(QWidget* parent = nullptr) : QDialog(parent) { this->setWindowTitle("JSON 表格编辑器"); - this->resize(600, 400); + this->resize(700, 450); setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint); // 去掉边框 //现在、、 //setAttribute(Qt::WA_TranslucentBackground); // 背景透明 this->setObjectName("JsonParamTableEditor"); @@ -25,8 +42,8 @@ public: m_tableWidget = new QTableWidget(0, 2, this); m_tableWidget->setHorizontalHeaderLabels({ "选项", "值" }); - fancyButtonText* okBtn = new fancyButtonText(70, 22, "保存", ""); - fancyButtonText* cancelBtn = new fancyButtonText(70, 22, "取消", ""); + fancyButtonText* okBtn = new fancyButtonText("保存", 70, 22, ""); + fancyButtonText* cancelBtn = new fancyButtonText("取消", 70, 22, ""); connect(okBtn, &QPushButton::clicked, this, &JsonParamTableEditor::onAccept); connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); @@ -40,35 +57,62 @@ public: mainLayout->addWidget(m_tableWidget); mainLayout->addLayout(btnLayout); + // 设置表格样式和属性 + m_tableWidget->setAlternatingRowColors(true); + m_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + m_tableWidget->horizontalHeader()->setStretchLastSection(true); + m_tableWidget->setColumnWidth(0, 200); // 选项列宽度 + m_tableWidget->setStyleSheet(QString(R"( QTableWidget { background-color: rgb(%1); font-family: "Microsoft YaHei"; - font-size: 12pt; color: #ffffff; + gridline-color: #555555; } QHeaderView::section { background-color: #0078d7; padding: 4px; font-weight: bold; + color: #ffffff; } - )").arg(sColor_Blue).arg(sColor_GoldWithBlack)); + QTableWidget::item:selected { + background-color: #0078d7; + } + )").arg(sColor_Blue)); } void setJsonObject(const nlohmann::json& json) { m_tableWidget->setRowCount(0); + m_originalJson = json; // 保存原始JSON + m_originalTypes.clear(); // 清空原始类型映射 + if (!json.is_object()) return; for (auto it = json.begin(); it != json.end(); ++it) { int row = m_tableWidget->rowCount(); m_tableWidget->insertRow(row); - m_tableWidget->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(it.key()))); - QString valueText = QString::fromStdString(it.value().dump()); - m_tableWidget->setItem(row, 1, new QTableWidgetItem(valueText)); + const std::string& key = it.key(); + const nlohmann::json& value = it.value(); + + // 设置键名(不可编辑) + QTableWidgetItem* keyItem = new QTableWidgetItem(QString::fromStdString(key)); + keyItem->setFlags(keyItem->flags() & ~Qt::ItemIsEditable); + keyItem->setBackground(QColor(80, 80, 80)); + m_tableWidget->setItem(row, 0, keyItem); + + // 确定类型(内部使用,不显示) + JsonValueType valueType = getJsonValueType(value); + m_originalTypes[key] = valueType; + + // 设置值(可编辑,但需要类型验证) + QString valueText = formatValueForDisplay(value, valueType); + QTableWidgetItem* valueItem = new QTableWidgetItem(valueText); + valueItem->setToolTip(generateTypeHint(valueType)); + m_tableWidget->setItem(row, 1, valueItem); } m_tableWidget->resizeColumnsToContents(); - } signals: @@ -90,24 +134,30 @@ private slots: QString key = keyItem->text().trimmed(); QString valStr = valItem->text().trimmed(); - if (key.isEmpty() || valStr.isEmpty()) { - QMessageBox::warning(this, "错误", QString("第 %1 行 key 或 value 为空").arg(row + 1)); + if (key.isEmpty()) { + QMessageBox::warning(this, "错误", QString("第 %1 行 key 为空").arg(row + 1)); return; } - if (valStr.size() > 10240) { - QMessageBox::warning(this, "错误", QString("第 %1 行的值过大").arg(row + 1)); + // 获取原始类型 + std::string keyStd = key.toStdString(); + if (m_originalTypes.find(keyStd) == m_originalTypes.end()) { + QMessageBox::warning(this, "错误", QString("第 %1 行找不到原始类型信息").arg(row + 1)); return; } - try { - result[key.toStdString()] = nlohmann::json::parse(valStr.toStdString()); - } - catch (const std::exception& e) { - QMessageBox::critical(this, "JSON 解析失败", - QString("第 %1 行 value 解析失败:\n%2").arg(row + 1).arg(e.what())); + JsonValueType expectedType = m_originalTypes[keyStd]; + + // 验证并转换值 + nlohmann::json convertedValue; + QString errorMsg; + if (!validateAndConvertValue(valStr, expectedType, convertedValue, errorMsg)) { + QMessageBox::critical(this, "类型验证失败", + QString("第 %1 行值验证失败:\n%2").arg(row + 1).arg(errorMsg)); return; } + + result[keyStd] = convertedValue; } emit jsonAccepted(result); @@ -116,6 +166,161 @@ private slots: private: QTableWidget* m_tableWidget; + nlohmann::json m_originalJson; // 保存原始JSON以便类型检查 + std::map m_originalTypes; // 保存每个键的原始类型 + + // 获取JSON值的类型 + JsonValueType getJsonValueType(const nlohmann::json& value) { + if (value.is_null()) return JsonValueType::Null; + if (value.is_boolean()) return JsonValueType::Boolean; + if (value.is_number()) return JsonValueType::Number; + if (value.is_string()) return JsonValueType::String; + if (value.is_array()) return JsonValueType::Array; + if (value.is_object()) return JsonValueType::Object; + return JsonValueType::String; // 默认为字符串 + } + + // 获取类型的显示名称 + QString getTypeDisplayName(JsonValueType type) { + switch (type) { + case JsonValueType::String: return "字符串"; + case JsonValueType::Number: return "数字"; + case JsonValueType::Boolean: return "布尔"; + case JsonValueType::Array: return "数组"; + case JsonValueType::Object: return "对象"; + case JsonValueType::Null: return "空值"; + default: return "未知"; + } + } + + // 格式化值用于显示 + QString formatValueForDisplay(const nlohmann::json& value, JsonValueType type) { + switch (type) { + case JsonValueType::String: + return QString::fromStdString(value.get()); + case JsonValueType::Number: + if (value.is_number_integer()) { + return QString::number(value.get()); + } else { + return QString::number(value.get()); + } + case JsonValueType::Boolean: + return value.get() ? "true" : "false"; + case JsonValueType::Array: + case JsonValueType::Object: + return QString::fromStdString(value.dump()); + case JsonValueType::Null: + return "null"; + default: + return QString::fromStdString(value.dump()); + } + } + + // 生成类型提示 + QString generateTypeHint(JsonValueType type) { + switch (type) { + case JsonValueType::String: + return "输入字符串值(不需要引号)"; + case JsonValueType::Number: + return "输入数字值(整数或小数)"; + case JsonValueType::Boolean: + return "输入布尔值(true 或 false)"; + case JsonValueType::Array: + return "输入JSON数组格式,如:[1,2,3] 或 [\"a\",\"b\"]"; + case JsonValueType::Object: + return "输入JSON对象格式,如:{\"key\":\"value\"}"; + case JsonValueType::Null: + return "空值(输入 null)"; + default: + return "请输入有效的JSON值"; + } + } + + // 验证并转换值 + bool validateAndConvertValue(const QString& input, JsonValueType expectedType, + nlohmann::json& result, QString& errorMsg) { + QString trimmedInput = input.trimmed(); + + // 长度检查 + if (trimmedInput.size() > 10240) { + errorMsg = "输入值过大(超过10240字符)"; + return false; + } + + try { + switch (expectedType) { + case JsonValueType::String: + result = trimmedInput.toStdString(); + return true; + + case JsonValueType::Number: { + bool ok; + // 先尝试整数 + int64_t intVal = trimmedInput.toLongLong(&ok); + if (ok) { + result = intVal; + return true; + } + // 再尝试浮点数 + double doubleVal = trimmedInput.toDouble(&ok); + if (ok && !std::isnan(doubleVal) && !std::isinf(doubleVal)) { + result = doubleVal; + return true; + } + errorMsg = "无效的数字格式"; + return false; + } + + case JsonValueType::Boolean: + if (trimmedInput.toLower() == "true") { + result = true; + return true; + } else if (trimmedInput.toLower() == "false") { + result = false; + return true; + } + errorMsg = "布尔值只能是 true 或 false"; + return false; + + case JsonValueType::Null: + if (trimmedInput.toLower() == "null") { + result = nullptr; + return true; + } + errorMsg = "空值只能是 null"; + return false; + + case JsonValueType::Array: + case JsonValueType::Object: { + // 对于数组和对象,尝试解析JSON + result = nlohmann::json::parse(trimmedInput.toStdString()); + + // 验证类型是否匹配 + if (expectedType == JsonValueType::Array && !result.is_array()) { + errorMsg = "期望数组格式,如:[1,2,3]"; + return false; + } + if (expectedType == JsonValueType::Object && !result.is_object()) { + errorMsg = "期望对象格式,如:{\"key\":\"value\"}"; + return false; + } + return true; + } + + default: + errorMsg = "未知的数据类型"; + return false; + } + } + catch (const nlohmann::json::parse_error& e) { + errorMsg = QString("JSON解析错误: %1").arg(e.what()); + return false; + } + catch (const std::exception& e) { + errorMsg = QString("转换错误: %1").arg(e.what()); + return false; + } + } }; diff --git a/src/launcher/GUI/front/auth.hpp b/src/launcher/GUI/front/auth.hpp index 1d8eb4f..b4889f7 100644 --- a/src/launcher/GUI/front/auth.hpp +++ b/src/launcher/GUI/front/auth.hpp @@ -1,44 +1,598 @@ -#include -#include +#pragma once + +#include +#include +#include #include -#include -struct authData{ - std::string user; - std::string passWord; -}; -class authDialog : public QDialog{ -public: - //INTERFACE - - //QLinedit +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include - enum authResult { - OK, - UserNotFound, - PassWordErr, - NoAuth, - CallBackRunFalse - }; - authResult auth(authData _authData){ - auto it = dataBase.find(_authData.user); - if (it == dataBase.end()) - return UserNotFound; - if (it->second.passWord == _authData.passWord) - return OK; - else - return PassWordErr; - } - authResult authWithCallback(authData _authData,std::function callBackFunc) { - authResult result = auth(_authData); - if (result == OK) { - if (callBackFunc() == false) - return CallBackRunFalse; - } - else - return result; - return OK; - } -private: - std::unordered_mapdataBase; -}; +namespace Auth { + // 用户等级枚举 + enum class UserLevel : int { + GUEST = 0, // 访客 + ADMIN = 1, // 普通用户 + ROOT = 2, // 超级管理员 + }; + + // 用户信息结构体 + struct UserInfo { + std::string username; + std::string password; + UserLevel level; + bool isActive; + std::string lastLoginTime; + + UserInfo() : username(""), password(""), level(UserLevel::GUEST), isActive(false), lastLoginTime("") {} + + UserInfo(const std::string& user, const std::string& pass, UserLevel lvl, bool active = true) + : username(user), password(pass), level(lvl), isActive(active), lastLoginTime("") {} + }; + + // 权限验证回调函数类型 + using AuthCallback = std::function; + + // 用户管理类 + class UserManager { + private: + inline static const std::string CONFIG_PATH = "./config/user.json"; + std::unordered_map users; + std::string currentLoggedUser; + UserLevel currentUserLevel; + bool isLoggedIn; + + // 私有方法实现 + void initializeDefaultUsers() { + // 创建默认管理员账户 + users["admin"] = UserInfo("admin", hashPassword("admin123"), UserLevel::ADMIN, true); + + // 创建默认访客账户 + users["guest"] = UserInfo("guest", hashPassword("guest123"), UserLevel::GUEST, true); + } + + bool loadUsersFromFile() { + try { + if (!std::filesystem::exists(CONFIG_PATH)) { + return false; + } + + nlohmann::json jsonData = readJsonFromPath(CONFIG_PATH); + if (jsonData.empty() || !jsonData.contains("users")) { + return false; + } + + users.clear(); + for (const auto& [username, userData] : jsonData["users"].items()) { + UserInfo user; + user.username = userData.value("username", ""); + user.password = userData.value("password", ""); + user.level = stringToUserLevel(userData.value("level", "GUEST")); + user.isActive = userData.value("isActive", true); + user.lastLoginTime = userData.value("lastLoginTime", ""); + + users[username] = user; + } + return true; + } + catch (const std::exception& e) { + std::cerr << "Error loading users from file: " << e.what() << std::endl; + return false; + } + } + + bool saveUsersToFile() { + try { + nlohmann::json jsonData; + nlohmann::json usersJson; + + for (const auto& [username, user] : users) { + nlohmann::json userJson; + userJson["username"] = user.username; + userJson["password"] = user.password; + userJson["level"] = userLevelToString(user.level); + userJson["isActive"] = user.isActive; + userJson["lastLoginTime"] = user.lastLoginTime; + + usersJson[username] = userJson; + } + + jsonData["users"] = usersJson; + jsonData["lastUpdate"] = getCurrentTimeString(); + + return saveJsonFromPath(CONFIG_PATH, jsonData); + } + catch (const std::exception& e) { + std::cerr << "Error saving users to file: " << e.what() << std::endl; + return false; + } + } + + std::string getCurrentTimeString() { + auto now = std::chrono::system_clock::now(); + auto time_t = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S"); + return ss.str(); + } + + std::string hashPassword(const std::string& password) { + // 简单的密码哈希实现(实际项目中应该使用更安全的哈希算法如bcrypt) + std::hash hasher; + size_t hashValue = hasher(password + "salt_string_2023"); + return std::to_string(hashValue); + } + + bool verifyPassword(const std::string& password, const std::string& hashedPassword) { + return hashPassword(password) == hashedPassword; + } + + public: + UserManager() : currentLoggedUser(""), currentUserLevel(UserLevel::GUEST), isLoggedIn(false) { + // 确保配置目录存在 + std::filesystem::path configDir = std::filesystem::path(CONFIG_PATH).parent_path(); + if (!std::filesystem::exists(configDir)) { + std::filesystem::create_directories(configDir); + } + + // 加载用户数据 + if (!loadUsersFromFile()) { + // 如果加载失败,初始化默认用户 + initializeDefaultUsers(); + saveUsersToFile(); + } + } + + ~UserManager() { + saveUsersToFile(); + } + + // 用户管理方法 + bool addUser(const std::string& username, const std::string& password, UserLevel level) { + if (username.empty() || password.empty()) { + std::cerr << "Username and password cannot be empty" << std::endl; + return false; + } + + if (userExists(username)) { + std::cerr << "User already exists: " << username << std::endl; + return false; + } + + UserInfo newUser(username, hashPassword(password), level, true); + users[username] = newUser; + + saveUsersToFile(); + return true; + } + + bool removeUser(const std::string& username) { + auto it = users.find(username); + if (it == users.end()) { + std::cerr << "User not found: " << username << std::endl; + return false; + } + + // 不允许删除当前登录用户 + if (isLoggedIn && currentLoggedUser == username) { + std::cerr << "Cannot remove currently logged in user" << std::endl; + return false; + } + + users.erase(it); + saveUsersToFile(); + return true; + } + + bool updateUserLevel(const std::string& username, UserLevel newLevel) { + auto it = users.find(username); + if (it == users.end()) { + std::cerr << "User not found: " << username << std::endl; + return false; + } + + it->second.level = newLevel; + + // 如果是当前登录用户,更新当前用户等级 + if (isLoggedIn && currentLoggedUser == username) { + currentUserLevel = newLevel; + } + + saveUsersToFile(); + return true; + } + + bool updateUserPassword(const std::string& username, const std::string& newPassword) { + auto it = users.find(username); + if (it == users.end()) { + std::cerr << "User not found: " << username << std::endl; + return false; + } + + if (newPassword.empty()) { + std::cerr << "Password cannot be empty" << std::endl; + return false; + } + + it->second.password = hashPassword(newPassword); + saveUsersToFile(); + return true; + } + + bool setUserActiveStatus(const std::string& username, bool isActive) { + auto it = users.find(username); + if (it == users.end()) { + std::cerr << "User not found: " << username << std::endl; + return false; + } + + it->second.isActive = isActive; + + // 如果禁用当前登录用户,则登出 + if (!isActive && isLoggedIn && currentLoggedUser == username) { + logout(); + } + + saveUsersToFile(); + return true; + } + + // 登录认证方法 + bool login(const std::string& username, const std::string& password) { + auto it = users.find(username); + if (it == users.end()) { + std::cerr << "User not found: " << username << std::endl; + return false; + } + + if (!it->second.isActive) { + std::cerr << "User account is disabled: " << username << std::endl; + return false; + } + + if (!verifyPassword(password, it->second.password)) { + std::cerr << "Invalid password for user: " << username << std::endl; + return false; + } + + // 登录成功 + currentLoggedUser = username; + currentUserLevel = it->second.level; + isLoggedIn = true; + + // 更新最后登录时间 + it->second.lastLoginTime = getCurrentTimeString(); + saveUsersToFile(); + + std::cout << "Login successful for user: " << username + << " (Level: " << userLevelToString(currentUserLevel) << ")" << std::endl; + return true; + } + + void logout() { + if (isLoggedIn) { + std::cout << "User logged out: " << currentLoggedUser << std::endl; + currentLoggedUser = ""; + currentUserLevel = UserLevel::GUEST; + isLoggedIn = false; + } + } + + bool isUserLoggedIn() const { + return isLoggedIn; + } + + std::string getCurrentUser() const { + return currentLoggedUser; + } + + UserLevel getCurrentUserLevel() const { + return currentUserLevel; + } + + // 权限验证方法 + bool hasPermission(UserLevel requiredLevel) const { + if (!isLoggedIn) { + return requiredLevel == UserLevel::GUEST; + } + return static_cast(currentUserLevel) >= static_cast(requiredLevel); + } + + void executeWithPermission(UserLevel requiredLevel, AuthCallback callback) { + if (hasPermission(requiredLevel)) { + callback(); + } else { + std::string errorMessage = "Access denied. Required level: " + userLevelToString(requiredLevel) + + ", Current level: " + userLevelToString(currentUserLevel); + std::cerr << errorMessage << std::endl; + + // 显示权限不足的弹窗 + QMessageBox::warning(nullptr, + "权限不足", + QString("您没有足够的权限执行此操作。\n\n需要权限级别: %1\n当前权限级别: %2") + .arg(QString::fromStdString(userLevelToString(requiredLevel))) + .arg(QString::fromStdString(userLevelToString(currentUserLevel)))); + } + } + + void executeWithPermission(UserLevel requiredLevel, AuthCallback callback, QWidget* parent) { + if (hasPermission(requiredLevel)) { + callback(); + } else { + std::string errorMessage = "Access denied. Required level: " + userLevelToString(requiredLevel) + + ", Current level: " + userLevelToString(currentUserLevel); + std::cerr << errorMessage << std::endl; + + // 显示权限不足的弹窗(指定父窗口) + QMessageBox::warning(parent, + QString::fromLocal8Bit("权限不足"), + QString::fromLocal8Bit("您没有足够的权限执行此操作。\n\n需要权限级别: %1\n当前权限级别: %2") + .arg(QString::fromStdString(userLevelToString(requiredLevel))) + .arg(QString::fromStdString(userLevelToString(currentUserLevel)))); + } + } + + void executeWithPermissionAndFallback(UserLevel requiredLevel, AuthCallback successCallback, AuthCallback failureCallback) { + if (hasPermission(requiredLevel)) { + successCallback(); + } else { + failureCallback(); + } + } + + // 用户信息查询方法 + bool userExists(const std::string& username) const { + return users.find(username) != users.end(); + } + + UserInfo getUserInfo(const std::string& username) const { + auto it = users.find(username); + if (it != users.end()) { + return it->second; + } + return UserInfo(); // 返回空的UserInfo + } + + std::vector getAllUsers() const { + std::vector userList; + for (const auto& [username, user] : users) { + userList.push_back(username); + } + return userList; + } + + std::vector getUsersByLevel(UserLevel level) const { + std::vector userList; + for (const auto& [username, user] : users) { + if (user.level == level) { + userList.push_back(username); + } + } + return userList; + } + + // 工具方法 + static std::string userLevelToString(UserLevel level) { + switch (level) { + case UserLevel::GUEST: return "GUEST"; + case UserLevel::ADMIN: return "ADMIN"; + case UserLevel::ROOT: return "ROOT"; + default: return "UNKNOWN"; + } + } + + static UserLevel stringToUserLevel(const std::string& levelStr) { + if (levelStr == "GUEST") return UserLevel::GUEST; + if (levelStr == "ADMIN") return UserLevel::ADMIN; + if (levelStr == "ROOT") return UserLevel::ROOT; + return UserLevel::GUEST; // 默认返回GUEST + } + + void printAllUsers() const { + std::cout << "\n=== All Users ===" << std::endl; + std::cout << std::left << std::setw(15) << "Username" + << std::setw(12) << "Level" + << std::setw(8) << "Active" + << std::setw(20) << "Last Login" << std::endl; + std::cout << std::string(55, '-') << std::endl; + + for (const auto& [username, user] : users) { + std::cout << std::left << std::setw(15) << username + << std::setw(12) << userLevelToString(user.level) + << std::setw(8) << (user.isActive ? "Yes" : "No") + << std::setw(20) << user.lastLoginTime << std::endl; + } + std::cout << std::endl; + } + + void printUserInfo(const std::string& username) const { + auto it = users.find(username); + if (it == users.end()) { + std::cout << "User not found: " << username << std::endl; + return; + } + + const UserInfo& user = it->second; + std::cout << "\n=== User Information ===" << std::endl; + std::cout << "Username: " << user.username << std::endl; + std::cout << "Level: " << userLevelToString(user.level) << std::endl; + std::cout << "Active: " << (user.isActive ? "Yes" : "No") << std::endl; + std::cout << "Last Login: " << user.lastLoginTime << std::endl; + std::cout << std::endl; + } + + // 批量操作方法 + bool importUsers(const std::string& filePath) { + try { + nlohmann::json jsonData = readJsonFromPath(filePath); + if (jsonData.empty() || !jsonData.contains("users")) { + return false; + } + + int importCount = 0; + for (const auto& [username, userData] : jsonData["users"].items()) { + if (!userExists(username)) { + UserInfo user; + user.username = userData.value("username", ""); + user.password = userData.value("password", ""); + user.level = stringToUserLevel(userData.value("level", "GUEST")); + user.isActive = userData.value("isActive", true); + user.lastLoginTime = userData.value("lastLoginTime", ""); + + users[username] = user; + importCount++; + } + } + + if (importCount > 0) { + saveUsersToFile(); + std::cout << "Imported " << importCount << " users successfully." << std::endl; + } + return importCount > 0; + } + catch (const std::exception& e) { + std::cerr << "Error importing users: " << e.what() << std::endl; + return false; + } + } + + bool exportUsers(const std::string& filePath) { + try { + nlohmann::json jsonData; + nlohmann::json usersJson; + + for (const auto& [username, user] : users) { + nlohmann::json userJson; + userJson["username"] = user.username; + userJson["password"] = user.password; + userJson["level"] = userLevelToString(user.level); + userJson["isActive"] = user.isActive; + userJson["lastLoginTime"] = user.lastLoginTime; + + usersJson[username] = userJson; + } + + jsonData["users"] = usersJson; + jsonData["exportTime"] = getCurrentTimeString(); + + return saveJsonFromPath(filePath, jsonData); + } + catch (const std::exception& e) { + std::cerr << "Error exporting users: " << e.what() << std::endl; + return false; + } + } + + void clearAllUsers() { + users.clear(); + logout(); + saveUsersToFile(); + } + + // 安全相关方法 + bool changePassword(const std::string& oldPassword, const std::string& newPassword) { + if (!isLoggedIn) { + std::cerr << "No user logged in" << std::endl; + return false; + } + + auto it = users.find(currentLoggedUser); + if (it == users.end()) { + std::cerr << "Current user not found in database" << std::endl; + return false; + } + + if (!verifyPassword(oldPassword, it->second.password)) { + std::cerr << "Invalid old password" << std::endl; + return false; + } + + if (newPassword.empty()) { + std::cerr << "New password cannot be empty" << std::endl; + return false; + } + + it->second.password = hashPassword(newPassword); + saveUsersToFile(); + std::cout << "Password changed successfully" << std::endl; + return true; + } + + std::vector getActiveUsers() const { + std::vector activeUsers; + for (const auto& [username, user] : users) { + if (user.isActive) { + activeUsers.push_back(username); + } + } + return activeUsers; + } + + int getUserCount() const { + return static_cast(users.size()); + } + + // 静态实例方法(单例模式) + static UserManager& getInstance() { + static UserManager instance; + return instance; + } + }; + + // 权限验证辅助函数 + namespace Utils { + inline void requirePermission(UserLevel requiredLevel, AuthCallback callback) { + UserManager::getInstance().executeWithPermission(requiredLevel, callback); + } + + inline void requirePermission(UserLevel requiredLevel, AuthCallback callback, QWidget* parent) { + UserManager::getInstance().executeWithPermission(requiredLevel, callback, parent); + } + + inline void requirePermissionWithMessage(UserLevel requiredLevel, AuthCallback callback, const std::string& errorMessage) { + if (UserManager::getInstance().hasPermission(requiredLevel)) { + callback(); + } else { + std::cerr << errorMessage << std::endl; + + // 显示自定义权限错误消息弹窗 + QMessageBox::warning(nullptr, + QString::fromLocal8Bit("权限不足"), + QString::fromLocal8Bit(errorMessage.c_str())); + } + } + + inline void requirePermissionWithMessage(UserLevel requiredLevel, AuthCallback callback, const std::string& errorMessage, QWidget* parent) { + if (UserManager::getInstance().hasPermission(requiredLevel)) { + callback(); + } else { + std::cerr << errorMessage << std::endl; + + // 显示自定义权限错误消息弹窗(指定父窗口) + QMessageBox::warning(parent, + QString::fromLocal8Bit("权限不足"), + QString::fromLocal8Bit(errorMessage.c_str())); + } + } + + inline bool checkCurrentUserPermission(UserLevel requiredLevel) { + return UserManager::getInstance().hasPermission(requiredLevel); + } + + inline std::string getPermissionErrorMessage(UserLevel requiredLevel, UserLevel currentLevel) { + return "Access denied. Required: " + UserManager::userLevelToString(requiredLevel) + + ", Current: " + UserManager::userLevelToString(currentLevel); + } + } + +} // namespace Auth \ No newline at end of file diff --git a/src/launcher/GUI/front/loadingWidget.h b/src/launcher/GUI/front/loadingWidget.h index b64f7fd..2461067 100644 --- a/src/launcher/GUI/front/loadingWidget.h +++ b/src/launcher/GUI/front/loadingWidget.h @@ -17,8 +17,8 @@ public: QLabel* sign = nullptr; QMovie* movie = nullptr; QTextEdit* initLog = nullptr; - fancyButtonText* retryBtn = new fancyButtonText(100,50,"重试","重新进行初始化"); - fancyButtonText* manualBtn = new fancyButtonText(180, 50, "离线模式", "离线模式"); + fancyButtonText* retryBtn = new fancyButtonText("重试", 100, 50, "重新进行初始化"); + fancyButtonText* manualBtn = new fancyButtonText("离线模式", 180, 50, "离线模式"); QGridLayout* glayout = new QGridLayout(this); QVBoxLayout* vlayout = new QVBoxLayout(this); loadingWidget(qtFuncBridge* bridgeIn) diff --git a/src/launcher/GUI/front/loginWindow.h b/src/launcher/GUI/front/loginWindow.h index 5a1f225..fb0114f 100644 --- a/src/launcher/GUI/front/loginWindow.h +++ b/src/launcher/GUI/front/loginWindow.h @@ -31,7 +31,7 @@ public: palette.setColor(QPalette::WindowText, Qt::white); layout= new QVBoxLayout(this); - button = new fancyButtonText(100,40,"确定",""); + button = new fancyButtonText("确定", 100, 40, ""); label=new QLabel("欢迎!"); label->setAlignment(Qt::AlignHCenter); @@ -56,7 +56,7 @@ public: passwordEdit.setFont(QFont("Microsoft YaHei", 12, QFont::Bold)); layout->addWidget(&passwordEdit); - exitBtn = new fancyButtonText(100, 40, u8"退出", ""); + exitBtn = new fancyButtonText(u8"退出", 100, 40, ""); QObject::connect(exitBtn, &QPushButton::clicked, [=]() { exit(0); }); diff --git a/src/launcher/GUI/front/pages/configSettingWidget.h b/src/launcher/GUI/front/pages/configSettingWidget.h deleted file mode 100644 index 7967b73..0000000 --- a/src/launcher/GUI/front/pages/configSettingWidget.h +++ /dev/null @@ -1,436 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "git_version.h" -#include -/**************格式****************/ -//... -//{ -// "showName":"Name", //仅显示 -// "valueName":"Name2",//检索 -// "value":"value" //值 -// "policy":"formatPolicy"//可选 格式检查 -// } -// ... -/***********************************/ -static bool isNumeric(const QString& str) { - QRegExp re("^-?\\d+(\\.\\d+)?([eE][-+]?\\d+)?$"); - return re.exactMatch(str); -} -class configSettingWidget :public QWidget -{ - Q_OBJECT -public: - enum formatPolicy - { - none, - filePath, - bhdPath, - IP, - number, - boolType, - path - }; - struct aLineData - { - int acessLevel; - std::string showName; - std::string value; - std::string formatPolicyStr; - formatPolicy _formatPolicy; - QWidget* userInputWidget; - std::string getValueFromQwidget() - { - switch (_formatPolicy) - { - case boolType: - if (((QCheckBox*)userInputWidget)->isChecked() == true) - return "true"; - else - return "flase"; - break; - default: - return ((QLineEdit*)userInputWidget)->text().toStdString(); - } - return "error"; - } - }; - QVBoxLayout* m_layout = new QVBoxLayout(this); - QHBoxLayout* btnLayout; - std::vectorbtns; - QLabel* icon, * Title; - int currentPageIndex = 0; - configSettingWidget(appConfig* _configIn):_config(_configIn){ - QPalette palette; - palette.setColor(QPalette::WindowText, Qt::white); - QFont font("微软雅黑", 24, QFont::Bold); - QFont font2("微软雅黑", 8, QFont::Bold); - - this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - this->setObjectName("configSettingWidget"); - //this->setStyleSheet(QString("QWidget {background-color: rgb(%1)}").arg(sColor_Gold)); - //this->showMaximized(); - m_layout->setContentsMargins(0, 0, 0, 0); - m_layout->setAlignment(Qt::AlignLeft|Qt::AlignTop); - - QHBoxLayout* titleLayout = new QHBoxLayout(); - Title = new QLabel(u8"设置"); - Title->setFont(font); - Title->setPalette(palette); - Title->setAlignment(Qt::AlignLeft); - - QLabel* versionShow = new QLabel(); - versionShow = new QLabel(QString(u8"当前版本:v%1 提交版本%2").arg(QString::fromStdString(softwareVersion)).arg(GIT_COMMIT_HASH)); - versionShow->setFont(font2); - versionShow->setPalette(palette); - versionShow->setAlignment(Qt::AlignLeft|Qt::AlignBottom); - - - titleLayout->addWidget(Title); - titleLayout->addWidget(versionShow); - titleLayout->setAlignment(Qt::AlignLeft | Qt::AlignBottom); - m_layout->addLayout(titleLayout); - - fancyButtonText* showConsoleBtn = new fancyButtonText(100, 30, "显示控制台", ""); - m_layout->addWidget(showConsoleBtn); - connect(showConsoleBtn, &QPushButton::clicked, [=]() { - ShowWindow(_config->consoleHandle, SW_SHOW); - }); - - fancyButtonText* hideConsoleBtn = new fancyButtonText(100, 30, "隐藏控制台", ""); - m_layout->addWidget(hideConsoleBtn); - connect(hideConsoleBtn, &QPushButton::clicked, [=]() { - ShowWindow(_config->consoleHandle, SW_HIDE); - }); - - m_layout->addWidget(&_hardwareInfoWidget); - - } -#if 0 - //格式检查 - bool formatPolicyCompare(formatPolicy _formatPolicy,QString compareStr,QString& textOut,QString &colorOut) - { - switch (_formatPolicy) - { - case path: - if (!isNumeric(compareStr)) - { - textOut = u8"格式错误,非数字"; - colorOut = "red"; - return true; - } - break; - case number: - if (!isNumeric(compareStr)) - { - textOut = u8"格式错误,非数字"; - colorOut = "red"; - return true; - } - break; - case filePath: - if (QFile(compareStr).exists() == false) - { - textOut = u8"路径错误!"; - colorOut = "red"; - return true; - } - break; - case bhdPath: - if (QFile(compareStr).exists() == false) - { - textOut = u8"路径错误!"; - colorOut = "red"; - return true; - } - if (compareStr.contains(".bhd") == false) - { - textOut = u8"不是一个模型文件!"; - colorOut = "red"; - return true; - } - break; - case IP: - if (QRegularExpression("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$").match(compareStr).hasMatch() == false) - { - textOut = u8"IP格式错误!"; - colorOut = "red"; - return true; - } - break; - } - return false; - } - void addConfigWidget(QString btnText,QString jsonPath) - { - int thistPageIndex = privateJsondatas.size(); - QPalette palette; - palette.setColor(QPalette::WindowText, Qt::white); - QFont font("微软雅黑", 13, QFont::Bold); - QFont font2("微软雅黑", 8); - QFont font3("微软雅黑", 16, QFont::Bold); - - //切换配置页面 - gradientButton* btn = new gradientButton(160,50, btnText, ""); - btnLayout->addWidget(btn); - btns.push_back(btn); - connect(btn, &QPushButton::clicked, [=]() - { - for (auto btnPtr : btns) - btnPtr->toDefault(); - btn->pressed(); - currentPageIndex = thistPageIndex; - stackedWidgets->setCurrentIndex(thistPageIndex); - }); - - //页面widget - QWidget* widget = new QWidget(); - stackedWidgets->addWidget(widget); - widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - QVBoxLayout* widgetLayout = new QVBoxLayout(widget); - widgetLayout->setContentsMargins(0, 0, 0, 0); - widgetLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); - - QScrollArea* scrollArea = new QScrollArea(); - widgetLayout->addWidget(scrollArea); - scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - scrollArea->setWidgetResizable(true); - scrollArea->setStyleSheet("QScrollArea { background-color: transparent; " - "border: 0px solid red;" - "border-radius: 0px;}"); - - QWidget* jsonWidget = new QWidget(); - jsonWidget->setObjectName("jsonWidget"); - jsonWidget->setStyleSheet("QWidget#jsonWidget { background-color: transparent; " - "border: 0px solid red;" - "border-radius: 0px;}"); - jsonWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - jsonWidget->setMaximumSize(9999 , 9999); - QGridLayout* jsonLayout = new QGridLayout(jsonWidget); - jsonLayout->setAlignment(Qt::AlignTop); - scrollArea->setWidget(jsonWidget); - jsonLayouts.push_back(jsonLayout); - - //参数列表读取以及初始化 - std::vector widgets; - std::vector< aLineData> jsonData=loadJson(jsonPath); - for (auto& data : jsonData) - { - QWidget* tempWidget = new QWidget(); - QVBoxLayout* tempVLayout = new QVBoxLayout(tempWidget); - tempVLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); - tempWidget->setContentsMargins(0, 0, 0, 0); - tempVLayout->setContentsMargins(0, 0, 0, 0); - - QLabel* showLabel = new QLabel(QString::fromStdString(data.showName)); - showLabel->setFont(font); - showLabel->setPalette(palette); - showLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); - - QLabel* warningLabel = new QLabel(""); - warningLabel->setFixedHeight(30); - warningLabel->setFont(font2); - - if (data._formatPolicy == boolType) - { - QCheckBox* checkBox = new QCheckBox(); - checkBox->setFont(font); - checkBox->setPalette(palette); - //checkBox->setFixedSize(QSize(50,50)); - - QHBoxLayout* tempLayout = new QHBoxLayout(); - tempLayout->addWidget(showLabel); - tempLayout->addWidget(checkBox); - tempVLayout->addLayout(tempLayout); - - tempVLayout->addWidget(warningLabel); - if (!data.value.compare("true")) - checkBox->setChecked(true); - data.userInputWidget = checkBox; - //修改时警告 - connect(checkBox, &QCheckBox::stateChanged, [=]() - { - if (checkBox->isChecked()==true && data.value =="false")//修改后的值不匹配 - { - warningLabel->setText("此项被修改!"); - warningLabel->setStyleSheet("color:yellow"); - checkBox->setStyleSheet("border: 2px solid yellow;"); - } - else if (checkBox->isChecked() == false && data.value == "true")//修改后的值不匹配 - { - warningLabel->setText("此项被修改!"); - warningLabel->setStyleSheet("color:yellow"); - checkBox->setStyleSheet("border: 2px solid yellow;"); - } - else - { - warningLabel->setText(""); - checkBox->setStyleSheet(""); - warningLabel->setText(""); - } - }); - } - else - { - QLineEdit* lineEdit = new QLineEdit(QString::fromStdString(data.value)); - lineEdit->setFont(font); - lineEdit->setPalette(palette); - lineEdit->setFixedWidth(500); - - tempVLayout->addWidget(showLabel); - tempVLayout->addWidget(lineEdit); - tempVLayout->addWidget(warningLabel); - data.userInputWidget = lineEdit; - //修改时警告 - connect(lineEdit, &QLineEdit::textChanged, [=]() - { - if (lineEdit->text().toStdString().compare(data.value))//修改后的值不匹配 - { - QString text, color; - if (formatPolicyCompare(data._formatPolicy, lineEdit->text(), text, color)) - { - warningLabel->setText(text); - warningLabel->setStyleSheet(QString("color:%1;").arg(color)); - lineEdit->setStyleSheet(QString("border: 2px solid %1;").arg(color)); - } - else - { - warningLabel->setText("此项被修改!"); - warningLabel->setStyleSheet("color:yellow"); - lineEdit->setStyleSheet("border: 2px solid yellow;"); - } - } - else - { - warningLabel->setText(""); - lineEdit->setStyleSheet(""); - warningLabel->setText(""); - } - }); - } - tempWidget->setFixedHeight(100); - widgets.push_back(tempWidget); - jsonLayout->addWidget(tempWidget); - } - privateWidgets.push_back(widgets); - privateJsondatas.push_back(jsonData); - //保存按钮 - fancyButtonText* saveBtn = new fancyButtonText(160, 50, u8"保存", u8"保存当前配置文件"); - connect(saveBtn, &QPushButton::clicked, this, [=]() {saveJson(jsonPath); }); - widgetLayout->addWidget(saveBtn); - } - void setMinimumSizePolicy(QWidget* widget) { - widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - for (QObject* child : widget->children()) { - QWidget* childWidget = qobject_cast(child); - if (childWidget) { - setMinimumSizePolicy(childWidget); - } - } - } - //读取json - std::vector< aLineData> loadJson(const QString& fileName) { - std::vector< aLineData> returnData; - nlohmann::json json = readJsonFromPath(fileName.toStdString()); - try - { - for (auto data : json) - { - aLineData lineData; - lineData.acessLevel = data["level"]; - lineData.showName = data["showName"]; - lineData.formatPolicyStr = data["policy"]; - lineData.value = data["value"]; - if (!lineData.formatPolicyStr.compare("filepath")) - lineData._formatPolicy = filePath; - else if (!lineData.formatPolicyStr.compare("bhdpath")) - lineData._formatPolicy = bhdPath; - else if (!lineData.formatPolicyStr.compare("ip")) - lineData._formatPolicy = IP; - else if (!lineData.formatPolicyStr.compare("number")) - lineData._formatPolicy = number; - else if (!lineData.formatPolicyStr.compare("bool")) - lineData._formatPolicy = boolType; - - returnData.push_back(lineData); - } - } - catch (...) - { - qDebug() << "read json failure" << fileName; - } - return returnData; - } - void updateLayout() - { - QMainWindow* mainWindow = qobject_cast(this->window()); - QSize stackedWidgetSize = mainWindow->size(); - int xCount = stackedWidgetSize.width() / 600; - if (xCount == 0) - return; - int eachWidth = stackedWidgetSize.width() / xCount; - std::vectoreachHeightCount(xCount, 0); - std::vectoreachHeightIndexCount(xCount, 0); - if (xCount == 1) - { - for (int i = 0; i < privateWidgets[currentPageIndex].size(); i++) - jsonLayouts[currentPageIndex]->addWidget(privateWidgets[currentPageIndex][i], i, 0); - } - for (int i = 0; i < privateWidgets[currentPageIndex].size(); i++) - { - int xIndex = 0; - for (xIndex = eachHeightCount.size() - 1; xIndex > 0; xIndex--) - if (eachHeightCount[xIndex - 1] > eachHeightCount[xIndex]) - { - break; - } - eachHeightCount[xIndex] += privateWidgets[currentPageIndex][i]->size().height(); - jsonLayouts[currentPageIndex]->addWidget(privateWidgets[currentPageIndex][i], eachHeightIndexCount[xIndex], xIndex); - eachHeightIndexCount[xIndex]++; - } - //jsonLayout->addLayout(classVLayout, jsonDataIndex, 0); - } - void saveJson(QString path) - { - // - nlohmann::json json; - for (auto& data : privateJsondatas[currentPageIndex]) - { - nlohmann::json eachJson; - eachJson["level"] = data.acessLevel; - eachJson["showName"] = data.showName; - eachJson["value"] = data.getValueFromQwidget(); - eachJson["policy"] = data.formatPolicyStr; - json.push_back(eachJson); - } - std::string sss = path.toStdString(); - saveJsonFromPath(sss, json); - } -#endif -protected: - -private: - appConfig* _config; - hardwareInfoWidget _hardwareInfoWidget; - std::vector> privateJsondatas;//路径与数据 - std::vector> privateWidgets;//路径与数据 - std::vectorjsonLayouts; -}; -#pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/dataAnalyzeWidget.h b/src/launcher/GUI/front/pages/dataAnalyzeWidget.h deleted file mode 100644 index 7c6c88c..0000000 --- a/src/launcher/GUI/front/pages/dataAnalyzeWidget.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/displayPageWidget.h b/src/launcher/GUI/front/pages/displayPageWidget.h index 52ecbd5..295ac53 100644 --- a/src/launcher/GUI/front/pages/displayPageWidget.h +++ b/src/launcher/GUI/front/pages/displayPageWidget.h @@ -2,7 +2,13 @@ #include #include #include +#include +#include +#include +#include +#include #include +#include #include #include #include @@ -15,10 +21,160 @@ #include #include #include -class displayWidget :public QWidget -{ +class toolBarWidget : public QWidget { Q_OBJECT public: + ConnectionWidget* _ConnectionWidget = new ConnectionWidget(this); + toolBarWidget(appConfig* config) :m_config(config) { + this->setObjectName("toolBarWidget"); + + Title = new QLabel(QString::fromStdString(config->_translation.translate("TOOLS"))); + Title->setObjectName("titleLabel"); + Title->setAlignment(Qt::AlignCenter); + Layout->addWidget(Title); + + QWidget* lineWidgetJustForShow = new QWidget(this); + lineWidgetJustForShow->setObjectName("lineWidgetJustForShow"); + lineWidgetJustForShow->setStyleSheet(R"( + QWidget#lineWidgetJustForShow { + background: rgb(32, 36, 40); + border-radius: 1px; /* 圆角半径 */ + } + )"); + lineWidgetJustForShow->setFixedWidth(5); + Layout->addWidget(lineWidgetJustForShow); + + // 创建按钮容器布局,用于后续添加按钮 + buttonsLayout = new QHBoxLayout(); + buttonsLayout->setSpacing(5); + buttonsLayout->setContentsMargins(0, 0, 0, 0); + Layout->addLayout(buttonsLayout); + + QWidget* spacerWidget = new QWidget; + spacerWidget->setMaximumWidth(2560); + Layout->addWidget(spacerWidget, 1); + + Layout->addWidget(_ConnectionWidget); + + this->setStyleSheet(R"( + toolBarWidget#toolBarWidget { + background-color: rgb(50, 55, 60); + border-radius: 10px; + border: 1px solid rgb(70, 75, 80); + } + QLabel#titleLabel { + color: white; + font-family: "微软雅黑"; + font-size: 20px; + font-weight: normal; + } + )"); + this->setFixedHeight(80); + } + // 通用的创建工具按钮函数实现 + bool createToolButton(const QString& iconPath, const QString& text, + std::function clickHandler, + const QSize& buttonSize = QSize(60, 60), const QSize& iconSize = QSize(30, 30)){ + + // 参数验证 + if (iconPath.isEmpty() || text.isEmpty() || !clickHandler) { + return false; + } + + // 创建布局 + QVBoxLayout* btnLayout = new QVBoxLayout(); + if (!btnLayout) { + return false; + } + + btnLayout->setSpacing(0); + btnLayout->setContentsMargins(0, 0, 0, 0); + + // 使用 QToolButton 来实现图标在上文字在下的效果 + QToolButton* btn = new QToolButton(this); + if (!btn) { + delete btnLayout; + return false; + } + + // 设置图标,检查图标是否加载成功 + QIcon icon(iconPath); + if (icon.isNull()) { + delete btn; + delete btnLayout; + return false; + } + + btn->setIcon(icon); + btn->setText(text); + btn->setIconSize(iconSize); + btn->setFixedSize(buttonSize.width() + 20, buttonSize.height() + 15); // 增加高度以容纳文字 + btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); // 文字在图标下方 + + // 设置按钮样式 + btn->setStyleSheet(R"( + QToolButton { + background-color: transparent; + border: none; + color: white; + font-family: "微软雅黑"; + font-size: 12px; + font-weight: bold; + } + QToolButton:hover { + background-color: black; + border-radius: 5px; + } + )"); + + btnLayout->addWidget(btn); + btnLayout->setAlignment(Qt::AlignCenter); + + // 连接点击事件 + if (!connect(btn, &QToolButton::clicked, clickHandler)) { + delete btn; + delete btnLayout; + return false; + } + + // 添加到按钮布局容器中 + buttonsLayout->addLayout(btnLayout); + + return true; + } + +protected: + // 重写paintEvent确保背景绘制 + void paintEvent(QPaintEvent* event) override { + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + // 绘制圆角矩形背景 + QPainterPath path; + path.addRoundedRect(this->rect(), 10, 10); + + // 设置背景色 + painter.fillPath(path, QBrush(QColor(50, 55, 60))); + + // 绘制边框 + QPen pen(QColor(70, 75, 80), 1); + painter.setPen(pen); + painter.drawPath(path); + + QWidget::paintEvent(event); + } + +private: + QLabel* Title; + QHBoxLayout* Layout = new QHBoxLayout(this); + QHBoxLayout* buttonsLayout; // 按钮容器布局 + appConfig* m_config; +}; + +class displayWidget :public QWidget{ + Q_OBJECT +public: + toolBarWidget* _toolBarWidget; QGridLayout* Layout; QLabel* icon, * Title; QWidget* leftWidget, * rightWidget1, * rightWidget2; @@ -30,7 +186,7 @@ public: dayNightShiftHistogramWidget* _dayNightShiftHistogramWidget; userSwitch* _userSwitch; softwareDataDisplay* _softwareDataDisplay; - ConnectionWidget* _ConnectionWidget = new ConnectionWidget(this); + runCommandWidget* _runCommandWidget; LogWindow* log = new LogWindow(); displayWidget(appConfig* config) :m_config(config){ @@ -45,13 +201,7 @@ public: leftWidget = new QWidget(); rightWidget1 = new QWidget(); rightWidget2 = new QWidget(); -#if switchToTongYongUi == 0 - Layout->addWidget(leftWidget, 0, 0); - //Layout->addWidget(rightWidget1, 0, 1); - Layout->addWidget(rightWidget2, 0, 1); - Layout->setColumnStretch(0, 3); - Layout->setColumnStretch(1, 1); -#else + Layout->addWidget(leftWidget, 0, 0); QWidget* lineWidgetJustForShow = new QWidget(this); lineWidgetJustForShow->setObjectName("lineWidgetJustForShow"); @@ -67,7 +217,9 @@ public: Layout->setColumnStretch(0, 9); Layout->setColumnStretch(1, 1); Layout->setColumnStretch(2, 3); -#endif + + _toolBarWidget = new toolBarWidget(config); + //Layout->setColumnStretch(2, 1); leftItemInit(config); rightItemInit1(); @@ -75,6 +227,7 @@ public: connectFunc(); //historyImgs->addData(true, "D:/CCD/yuantu/2024-06-04/23H/TEST/1 (1).bmp", QPixmap("D:/CCD/yuantu/2024-06-04/23H/TEST/1 (1).bmp")); } + void rightItemInit1(){ QVBoxLayout* hLayout = new QVBoxLayout(rightWidget1); hLayout->addWidget(historyImgs); @@ -134,73 +287,20 @@ public: vLayout->setContentsMargins(0, 0, 0, 0); QWidget* titleWidget = new QWidget(this); - QHBoxLayout* titleLayout = new QHBoxLayout(titleWidget); - titleWidget->setObjectName("titleWidget"); - -#if switchToTongYongUi == 1 - titleWidget->setStyleSheet(R"( - QWidget#titleWidget { - background: rgb(50, 55, 60); - border-radius: 10px; /* 圆角半径 */ - } - )"); -#endif - -#if switchToTongYongUi == 0 - Title = new QLabel(u8"主界面"); - Title->setFont(font); - Title->setPalette(palette); - Title->setAlignment(Qt::AlignLeft); -#else - Title = new QLabel(u8"工
具"); - Title->setFont(font2); - Title->setPalette(palette); - Title->setAlignment(Qt::AlignCenter); - titleLayout->addWidget(Title); - - QWidget* lineWidgetJustForShow = new QWidget(this); - lineWidgetJustForShow->setObjectName("lineWidgetJustForShow"); - lineWidgetJustForShow->setStyleSheet(R"( - QWidget#lineWidgetJustForShow { - background: rgb(32, 36, 40); - border-radius: 1px; /* 圆角半径 */ - } - )"); - lineWidgetJustForShow->setFixedWidth(5); - titleLayout->addWidget(lineWidgetJustForShow); QFont font3("微软雅黑", 10, QFont::Bold); #pragma region 日志分析按钮 { - QVBoxLayout* btnLayout = new QVBoxLayout(); - QPushButton* btn = new QPushButton(this); - btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/4.LogAnalyze.png")); - btn->setFixedSize(QSize(50, 50)); - btn->setIconSize(QSize(25, 25)); - btn->setStyleSheet(R"( - QPushButton { - background-color: transparent; - border: none; - } - QPushButton:hover { - background-color: black; - border-radius: 5px; - } - )"); - QLabel* text = new QLabel("日志分析"); - text->setFont(font3); - text->setPalette(palette); - btnLayout->addWidget(btn); - btnLayout->addWidget(text); - titleLayout->addLayout(btnLayout); - connect(btn, &QPushButton::clicked, [=]() { - emit changeStackWidget(2); + _toolBarWidget->createToolButton(":/TongYongUiIcon/TongYongUiIcon/4.LogAnalyze.png", + QString::fromStdString(config->_translation.translate("Log")), + [=]() { + emit changeStackWidget(2); }); } #pragma endregion #pragma region 打开配置文件按钮 { - QVBoxLayout* btnLayout = new QVBoxLayout(); + /*QVBoxLayout* btnLayout = new QVBoxLayout(); QPushButton* btn = new QPushButton(this); btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/9.paramSetting.png")); btn->setFixedSize(QSize(50, 50)); @@ -215,7 +315,7 @@ public: border-radius: 5px; } )"); - QLabel* text = new QLabel("配置文件"); + QLabel* text = new QLabel(config->_translation.translate("SettingJson")); text->setFont(font3); text->setPalette(palette); btnLayout->addWidget(btn); @@ -223,106 +323,48 @@ public: titleLayout->addLayout(btnLayout); connect(btn, &QPushButton::clicked, [=]() { QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(config->settingJsonPath))); - }); + });*/ } #pragma endregion #pragma region 结果图查看按钮 { - QVBoxLayout* btnLayout = new QVBoxLayout(); - QPushButton* btn = new QPushButton(this); - btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/23.1.imageView.png")); - btn->setIconSize(QSize(50, 50)); - btn->setStyleSheet(R"( - QPushButton { - background-color: transparent; - border: none; - } - QPushButton:hover { - background-color: black; - border-radius: 5px; - } - )"); - QLabel* text = new QLabel("结果图查看"); - text->setFont(font3); - text->setPalette(palette); - btnLayout->addWidget(btn); - btnLayout->addWidget(text); - titleLayout->addLayout(btnLayout); - connect(btn, &QPushButton::clicked, [=]() { - QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(config->imgSavePath))); - }); + _toolBarWidget->createToolButton(":/TongYongUiIcon/TongYongUiIcon/23.1.imageView.png", + QString::fromStdString(config->_translation.translate("ViewImage")), + [=]() { + QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(config->imgSavePath))); + }); } #pragma endregion #pragma region 修改检测参数按钮 { - QVBoxLayout* btnLayout = new QVBoxLayout(); - QPushButton* btn = new QPushButton(this); - btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/search_1.png")); - btn->setFixedSize(QSize(75, 50)); - btn->setIconSize(QSize(25, 25)); - btn->setStyleSheet(R"( - QPushButton { - background-color: transparent; - border: none; - } - QPushButton:hover { - background-color: black; - border-radius: 5px; - } - )"); - QLabel* text = new QLabel("修改检测参数"); - text->setFont(font3); - text->setPalette(palette); - btnLayout->addWidget(btn); - btnLayout->addWidget(text); - titleLayout->addLayout(btnLayout); - connect(btn, &QPushButton::clicked, [=]() { - JsonParamTableEditor* dlg = new JsonParamTableEditor(this); - dlg->setJsonObject(m_config->settingJson["backend"]["missionSettings"]), - dlg->setAttribute(Qt::WA_DeleteOnClose); - connect(dlg, &JsonParamTableEditor::jsonAccepted, [this](const nlohmann::json& result) { - m_config->settingJson["backend"]["missionSettings"] = result; - }); - dlg->show(); }); + _toolBarWidget->createToolButton(":/TongYongUiIcon/TongYongUiIcon/search_1.png", + QString::fromStdString(config->_translation.translate("Param")), + [=]() { + config->Authorization.executeWithPermission(Auth::UserLevel::ADMIN,[this]() { + JsonParamTableEditor* dlg = new JsonParamTableEditor(this); + dlg->setJsonObject(m_config->settingJson["backend"]["algorithmSettings"]); + dlg->setAttribute(Qt::WA_DeleteOnClose); + connect(dlg, &JsonParamTableEditor::jsonAccepted, [this](const nlohmann::json& result) { + m_config->settingJson["backend"]["algorithmSettings"] = result; + }); + dlg->show(); + }); + }); } #pragma endregion #pragma region 故障排查按钮 { - QVBoxLayout* btnLayout = new QVBoxLayout(); - QPushButton* btn = new QPushButton(this); - btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/18.help.png")); - btn->setFixedSize(QSize(50, 50)); - btn->setIconSize(QSize(25, 25)); - btn->setStyleSheet(R"( - QPushButton { - background-color: transparent; - border: none; - } - QPushButton:hover { - background-color: black; - border-radius: 5px; - } - )"); - QLabel* text = new QLabel("故障排查"); - text->setFont(font3); - text->setPalette(palette); - btnLayout->addWidget(btn); - btnLayout->addWidget(text); - titleLayout->addLayout(btnLayout); _runCommandWidget = new runCommandWidget(); - connect(btn, &QPushButton::clicked, [=]() { - _runCommandWidget->show(); - _runCommandWidget->raise(); + _toolBarWidget->createToolButton(":/TongYongUiIcon/TongYongUiIcon/18.help.png", + QString::fromStdString(config->_translation.translate("Debug")), + [=]() { + _runCommandWidget->show(); + _runCommandWidget->raise(); }); } #pragma endregion - QWidget* spacerWidget = new QWidget; - spacerWidget->setMaximumWidth(1920); - titleLayout->addWidget(spacerWidget, 1); -#endif - - titleLayout->addWidget(_ConnectionWidget); - vLayout->addWidget(titleWidget); + + vLayout->addWidget(_toolBarWidget); vLayout->addWidget(&_ImageWidgetManager); _ImageWidgetManager.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -345,6 +387,8 @@ public: this, &displayWidget::historyClick); } + + public slots: void recvMainWindowStdLogMsg(QString msg) { diff --git a/src/launcher/GUI/front/pages/logPageWidget.h b/src/launcher/GUI/front/pages/logPageWidget.h index 9589b8a..48b435c 100644 --- a/src/launcher/GUI/front/pages/logPageWidget.h +++ b/src/launcher/GUI/front/pages/logPageWidget.h @@ -15,18 +15,41 @@ #include #include #include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include //行数上限 const int MAX_LOGWIDGET_LINES = 1000; class logWidget : public QWidget { + Q_OBJECT + public: enum logType { stdConsle, qtConsle }; + +private: + // 用于存储过滤器状态 + struct FilterState { + QComboBox* levelFilter; + QLineEdit* regexFilter; + QPlainTextEdit* textWidget; + QStringList allMessages; // 存储所有原始消息 + bool autoScroll = true; + }; + + std::unordered_map filterStates; + +public: QVBoxLayout* Layout; QHBoxLayout* btnLayout; std::vector btns; @@ -44,7 +67,7 @@ public: widgets->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - this->setObjectName("configSettingWidget"); + this->setObjectName("settingWidget"); Layout = new QVBoxLayout(this); Layout->setContentsMargins(0, 0, 0, 0); @@ -65,8 +88,21 @@ public: qtConsoleOutput.setReadOnly(true); stdConsoleOutput.setMaximumBlockCount(MAX_LOGWIDGET_LINES); qtConsoleOutput.setMaximumBlockCount(MAX_LOGWIDGET_LINES); - stdConsoleOutput.setStyleSheet("background-color: rgb(30,30,30); color: white;"); - qtConsoleOutput.setStyleSheet("background-color: rgb(30,30,30); color: white;"); + + QString textEditStyle = R"( + QPlainTextEdit { + background-color: rgb(30,30,30); + color: white; + border: 1px solid #555555; + border-radius: 3px; + font-family: "Consolas", "Courier New", monospace; + font-size: 10px; + line-height: 1.2; + } + )"; + + stdConsoleOutput.setStyleSheet(textEditStyle); + qtConsoleOutput.setStyleSheet(textEditStyle); addLogWidget(u8"控制台", &stdConsoleOutput, logType::stdConsle); addLogWidget(u8"QT日志", &qtConsoleOutput, logType::qtConsle); @@ -89,7 +125,7 @@ public: btnPtr->toDefault(); btn->pressed(); widgets->setCurrentIndex(index); - }); + }); QWidget* widget = new QWidget(); widgets->addWidget(widget); @@ -99,27 +135,94 @@ public: widgetLayout->setContentsMargins(0, 0, 0, 0); widgetLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); + // 第一行工具栏:过滤器 QHBoxLayout* toolHLayout = new QHBoxLayout(); widgetLayout->addLayout(toolHLayout); - QLabel* toolName = new QLabel(u8"过滤器"); + QLabel* toolName = new QLabel(u8"日志级别:"); toolName->setFont(font2); toolName->setPalette(palette); toolHLayout->addWidget(toolName); - QStringList options = { "Debug","Info","Warning" }; + QStringList options = { "全部", "Debug", "Info", "Warning", "Error" }; QComboBox* filterSelector = new QComboBox(); filterSelector->addItems(options); toolHLayout->addWidget(filterSelector); - QLabel* toolName2 = new QLabel(u8" 正则匹配"); + QLabel* toolName2 = new QLabel(u8"正则匹配:"); toolName2->setFont(font2); toolName2->setPalette(palette); toolHLayout->addWidget(toolName2); QLineEdit* lineedit = new QLineEdit(); + lineedit->setPlaceholderText("输入正则表达式..."); toolHLayout->addWidget(lineedit); + // 第二行工具栏:功能按钮 + QHBoxLayout* toolHLayout2 = new QHBoxLayout(); + widgetLayout->addLayout(toolHLayout2); + + QPushButton* saveBtn = new QPushButton("保存日志"); + QPushButton* clearBtn = new QPushButton("清空"); + QPushButton* autoScrollBtn = new QPushButton("自动滚动"); + autoScrollBtn->setCheckable(true); + autoScrollBtn->setChecked(true); + + saveBtn->setFixedSize(80, 25); + clearBtn->setFixedSize(60, 25); + autoScrollBtn->setFixedSize(80, 25); + + // 设置按钮样式 + QString buttonStyle = R"( + QPushButton { + background-color: #0078d7; + color: white; + border: 1px solid #005a9e; + border-radius: 3px; + font-size: 10px; + } + QPushButton:hover { + background-color: #106ebe; + } + QPushButton:pressed { + background-color: #005a9e; + } + QPushButton:checked { + background-color: #005a9e; + border: 2px solid #0078d7; + } + )"; + + saveBtn->setStyleSheet(buttonStyle); + clearBtn->setStyleSheet(buttonStyle); + autoScrollBtn->setStyleSheet(buttonStyle); + + toolHLayout2->addWidget(saveBtn); + toolHLayout2->addWidget(clearBtn); + toolHLayout2->addWidget(autoScrollBtn); + toolHLayout2->addStretch(); + + // 存储过滤器状态 + FilterState& state = filterStates[index]; + state.levelFilter = filterSelector; + state.regexFilter = lineedit; + state.textWidget = textWidget; + state.autoScroll = true; + + // 连接过滤器信号 + connect(filterSelector, QOverload::of(&QComboBox::currentIndexChanged), + [this, index]() { applyFilters(index); }); + + connect(lineedit, &QLineEdit::textChanged, + [this, index]() { applyFilters(index); }); + + // 连接功能按钮 + connect(saveBtn, &QPushButton::clicked, [this, index]() { saveLogToFile(index); }); + connect(clearBtn, &QPushButton::clicked, [this, index]() { clearLog(index); }); + connect(autoScrollBtn, &QPushButton::toggled, [this, index](bool checked) { + filterStates[index].autoScroll = checked; + }); + widgetLayout->addWidget(textWidget); } @@ -131,15 +234,167 @@ public: return QTime::currentTime().toString("HH:mm:ss.zzz"); } +private: + // 应用过滤器 + void applyFilters(int index) { + if (filterStates.find(index) == filterStates.end()) return; + + FilterState& state = filterStates[index]; + QString levelFilter = state.levelFilter->currentText(); + QString regexPattern = state.regexFilter->text(); + + // 清空当前显示 + state.textWidget->clear(); + + QRegularExpression regex; + if (!regexPattern.isEmpty()) { + regex.setPattern(regexPattern); + if (!regex.isValid()) { + state.textWidget->appendPlainText("正则表达式无效: " + regexPattern); + return; + } + } + + // 过滤并显示消息 + for (const QString& message : state.allMessages) { + bool shouldShow = true; + + // 级别过滤 + if (levelFilter != "全部") { + if (!message.contains(levelFilter, Qt::CaseInsensitive)) { + shouldShow = false; + } + } + + // 正则过滤 + if (shouldShow && !regexPattern.isEmpty()) { + if (!regex.match(message).hasMatch()) { + shouldShow = false; + } + } + + if (shouldShow) { + // 根据日志级别设置颜色 + appendColoredMessage(state.textWidget, message); + } + } + + // 自动滚动到底部 + if (state.autoScroll) { + scrollToBottom(state.textWidget); + } + } + + // 添加带颜色的消息 + void appendColoredMessage(QPlainTextEdit* textEdit, const QString& message) { + QTextCursor cursor = textEdit->textCursor(); + cursor.movePosition(QTextCursor::End); + + QTextCharFormat format; + format.setForeground(QColor(255, 255, 255)); // 默认白色 + + // 根据关键词设置颜色 + if (message.contains("Error", Qt::CaseInsensitive) || + message.contains("错误", Qt::CaseInsensitive)) { + format.setForeground(QColor(255, 100, 100)); // 红色 + } else if (message.contains("Warning", Qt::CaseInsensitive) || + message.contains("警告", Qt::CaseInsensitive)) { + format.setForeground(QColor(255, 200, 100)); // 橙色 + } else if (message.contains("Info", Qt::CaseInsensitive) || + message.contains("信息", Qt::CaseInsensitive)) { + format.setForeground(QColor(100, 200, 255)); // 蓝色 + } else if (message.contains("Debug", Qt::CaseInsensitive) || + message.contains("调试", Qt::CaseInsensitive)) { + format.setForeground(QColor(150, 150, 150)); // 灰色 + } + + cursor.setCharFormat(format); + cursor.insertText(message + "\n"); + textEdit->setTextCursor(cursor); + } + + // 滚动到底部 + void scrollToBottom(QPlainTextEdit* textEdit) { + QScrollBar* scrollBar = textEdit->verticalScrollBar(); + scrollBar->setValue(scrollBar->maximum()); + } + + // 保存日志到文件 + void saveLogToFile(int index) { + if (filterStates.find(index) == filterStates.end()) return; + + QString fileName = QFileDialog::getSaveFileName( + this, + "保存日志文件", + QString("log_%1.txt").arg(getCurrentDate()), + "文本文件 (*.txt);;所有文件 (*.*)" + ); + + if (!fileName.isEmpty()) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&file); + out.setCodec("UTF-8"); + out << filterStates[index].textWidget->toPlainText(); + file.close(); + QMessageBox::information(this, "成功", "日志已保存到: " + fileName); + } else { + QMessageBox::warning(this, "错误", "无法保存文件: " + fileName); + } + } + } + + // 清空日志 + void clearLog(int index) { + if (filterStates.find(index) == filterStates.end()) return; + + auto reply = QMessageBox::question(this, "确认", "确定要清空当前日志吗?", + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + filterStates[index].allMessages.clear(); + filterStates[index].textWidget->clear(); + } + } + public slots: void recvStdLogMsg(QString logMsg) { QString text = getCurrentDate() + " " + getCurrentTime() + " " + logMsg; - stdConsoleOutput.appendPlainText(text); + + // 添加到标准控制台 (索引0) + if (filterStates.find(0) != filterStates.end()) { + filterStates[0].allMessages.append(text); + + // 如果当前显示的是标准控制台,应用过滤器显示 + if (widgets->currentIndex() == 0) { + applyFilters(0); + } + } else { + // 兜底:直接添加到文本框 + stdConsoleOutput.appendPlainText(text); + if (filterStates.size() > 0 && filterStates[0].autoScroll) { + scrollToBottom(&stdConsoleOutput); + } + } } void recvQtLogMsg(QString logMsg) { QString text = getCurrentDate() + " " + getCurrentTime() + " " + logMsg; - qtConsoleOutput.appendPlainText(text); + + // 添加到Qt日志 (索引1) + if (filterStates.find(1) != filterStates.end()) { + filterStates[1].allMessages.append(text); + + // 如果当前显示的是Qt日志,应用过滤器显示 + if (widgets->currentIndex() == 1) { + applyFilters(1); + } + } else { + // 兜底:直接添加到文本框 + qtConsoleOutput.appendPlainText(text); + if (filterStates.size() > 1 && filterStates[1].autoScroll) { + scrollToBottom(&qtConsoleOutput); + } + } } }; #pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/manualDetWidget.h b/src/launcher/GUI/front/pages/manualDetWidget.h index 024c8d6..785614f 100644 --- a/src/launcher/GUI/front/pages/manualDetWidget.h +++ b/src/launcher/GUI/front/pages/manualDetWidget.h @@ -12,8 +12,7 @@ #include #include -class manualDetWidget : public QWidget -{ +class manualDetWidget : public QWidget{ Q_OBJECT public: @@ -33,9 +32,8 @@ public: QComboBox* algoSelect = new QComboBox(this); QTextEdit* logWidget = new QTextEdit(this); //manualDetThread* _manualDetThread = new manualDetThread(imgPathEdit, algoSelect, logWidget); - fancyButtonText* startEvaluateBtn = new fancyButtonText(100,60,"检测",""); - void titleInit() - { + fancyButtonText* startEvaluateBtn = new fancyButtonText("检测",100,60,""); + void titleInit(){ QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); QFont font("微软雅黑", 24, QFont::Bold); @@ -62,8 +60,7 @@ public: btnLayout->setContentsMargins(0, 0, 0, 0); btnLayout->setAlignment(Qt::AlignLeft); } - void mainWidgetInit() - { + void mainWidgetInit(){ QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); QFont font("微软雅黑", 18, QFont::Bold); @@ -112,8 +109,7 @@ public: leftMainLayout->addWidget(startEvaluateBtn); } - manualDetWidget() - { + manualDetWidget(){ titleInit(); mainWidgetInit(); logWidget->setReadOnly(true); diff --git a/src/launcher/GUI/front/pages/pluginManagerWidget.hpp b/src/launcher/GUI/front/pages/pluginManagerWidget.hpp index 8b156ec..c7b7aad 100644 --- a/src/launcher/GUI/front/pages/pluginManagerWidget.hpp +++ b/src/launcher/GUI/front/pages/pluginManagerWidget.hpp @@ -36,8 +36,7 @@ public: pluginUnit(std::string name, std::string describe = "没有描述") - :deleteBtn(80, 40, "X"), interfaceBtn(80, 40, "interface") - { + :deleteBtn("X", 80, 40), interfaceBtn("interface", 80, 40){ layout = new QVBoxLayout(this); QFont font("微软雅黑", 24, QFont::Bold); QFont font2("微软雅黑", 18, QFont::Thin); @@ -78,14 +77,12 @@ public: } }; //插件管理界面 -class pluginConfigureWidget : public QWidget -{ +class pluginConfigureWidget : public QWidget{ Q_OBJECT public: QGridLayout* layout; int maxUnitPerX = 5, maxUnitPerY = 4; - pluginConfigureWidget() - { + pluginConfigureWidget(){ layout = new QGridLayout(this); //this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); this->setObjectName("pluginManagerListWidget"); @@ -138,8 +135,7 @@ public: QString name; pluginConfigureWidget mainWidget; pluginManagerWidget() : - pluginImportBtn(120, 50, "导入", "") - { + pluginImportBtn("导入", 120, 50, ""){ QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); QFont font("微软雅黑", 24, QFont::Bold); diff --git a/src/launcher/GUI/front/pages/settingWidget.h b/src/launcher/GUI/front/pages/settingWidget.h new file mode 100644 index 0000000..ca9bcdc --- /dev/null +++ b/src/launcher/GUI/front/pages/settingWidget.h @@ -0,0 +1,394 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "git_version.h" +#include +#include +#include +#include + +class settingWidget :public QWidget{ + Q_OBJECT +public: + + QVBoxLayout* m_layout; + QScrollArea* scrollArea; + QWidget* contentWidget; + QHBoxLayout* btnLayout; + std::vectorbtns; + QLabel* icon, * Title; + int currentPageIndex = 0; + settingWidget(appConfig* _configIn):_config(_configIn){ + QPalette palette; + palette.setColor(QPalette::WindowText, Qt::white); + QFont font("微软雅黑", 24, QFont::Bold); + QFont font2("微软雅黑", 8, QFont::Bold); + + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + this->setObjectName("settingWidget"); + this->setStyleSheet(R"( + QWidget#settingWidget { + background: rgb(40, 45, 50); + } + )"); + + // 创建主布局 + QVBoxLayout* mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + + // 创建滚动区域 + scrollArea = new QScrollArea(); + scrollArea->setObjectName("configScrollArea"); + scrollArea->setStyleSheet(R"( + QScrollArea#configScrollArea { + border: none; + background: transparent; + } + QScrollBar:vertical { + background: rgb(60, 65, 70); + width: 12px; + border-radius: 6px; + } + QScrollBar::handle:vertical { + background: rgb(100, 105, 110); + border-radius: 6px; + min-height: 20px; + } + QScrollBar::handle:vertical:hover { + background: rgb(120, 125, 130); + } + )"); + scrollArea->setWidgetResizable(true); + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + // 创建内容容器 + contentWidget = new QWidget(); + contentWidget->setObjectName("contentWidget"); + contentWidget->setStyleSheet("QWidget#contentWidget { background: transparent; }"); + + m_layout = new QVBoxLayout(contentWidget); + m_layout->setContentsMargins(20, 20, 20, 20); + m_layout->setSpacing(15); + m_layout->setAlignment(Qt::AlignLeft|Qt::AlignTop); + + // 创建标题区域容器 + QWidget* titleWidget = new QWidget(); + titleWidget->setObjectName("titleWidget"); + titleWidget->setStyleSheet(R"( + QWidget#titleWidget { + background: rgb(50, 55, 60); + border-radius: 10px; + padding: 15px; + } + )"); + + QVBoxLayout* titleContainerLayout = new QVBoxLayout(titleWidget); + titleContainerLayout->setContentsMargins(15, 15, 15, 15); + titleContainerLayout->setSpacing(10); + + // 主标题和版本信息布局 + QHBoxLayout* titleLayout = new QHBoxLayout(); + titleLayout->setContentsMargins(0, 0, 0, 0); + + Title = new QLabel(QString::fromStdString(_config->_translation.translate("Setting"))); + Title->setFont(font); + Title->setPalette(palette); + Title->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + + QLabel* versionShow = new QLabel(QString(u8"当前版本: v%1 | 提交版本: %2").arg(QString::fromStdString(softwareVersion)).arg(GIT_COMMIT_HASH)); + versionShow->setFont(font2); + versionShow->setPalette(palette); + versionShow->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + versionShow->setStyleSheet("color: rgb(180, 180, 180);"); + + titleLayout->addWidget(Title); + titleLayout->addStretch(); + titleLayout->addWidget(versionShow); + + titleContainerLayout->addLayout(titleLayout); + m_layout->addWidget(titleWidget); + //语言设置 + { + // 创建语言设置分组容器 + QGroupBox* languageGroupBox = new QGroupBox(QString::fromStdString(_config->_translation.translate("Language Settings"))); + languageGroupBox->setObjectName("languageGroupBox"); + languageGroupBox->setStyleSheet(R"( + QGroupBox#languageGroupBox { + background: rgb(50, 55, 60); + border-radius: 10px; + font-family: "微软雅黑"; + font-size: 14px; + font-weight: bold; + color: white; + padding-top: 20px; + } + QGroupBox#languageGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 10px 0 10px; + } + )"); + + QVBoxLayout* languageMainLayout = new QVBoxLayout(languageGroupBox); + languageMainLayout->setContentsMargins(15, 15, 15, 15); + languageMainLayout->setSpacing(10); + + QHBoxLayout* languageSelectLayout = new QHBoxLayout(); + languageSelectLayout->setSpacing(15); + + QLabel* languageSelectLabel = new QLabel(u8"选择语言/Language/Bahasa:"); + languageSelectLabel->setFont(font2); + languageSelectLabel->setPalette(palette); + languageSelectLabel->setMinimumWidth(200); + + QComboBox* languageSelect = new QComboBox(); + languageSelect->setMinimumWidth(150); + languageSelect->setStyleSheet(R"( + QComboBox { + background-color: rgb(70, 75, 80); + border: 2px solid rgb(100, 105, 110); + border-radius: 5px; + padding: 5px; + color: white; + font-family: "微软雅黑"; + font-size: 12px; + } + QComboBox:hover { + border-color: rgb(120, 125, 130); + } + QComboBox::drop-down { + border: none; + } + QComboBox::down-arrow { + image: url(:/icons/down-arrow.png); + } + )"); + + auto languagesKeys = _configIn->_translation.getSections(); + int index = 0; + for (int i = 0; i < languagesKeys.size(); i++) { + languageSelect->addItem(QString::fromStdString(languagesKeys[i])); + if (languagesKeys[i] == _configIn->_translation.getCurrentLanguage()) + index = i; + } + languageSelect->setCurrentIndex(index); + + QLabel* languageSelectTip = new QLabel(); + languageSelectTip->setFont(font2); + languageSelectTip->setPalette(palette); + languageSelectTip->setStyleSheet("color: rgb(255, 200, 100);"); + + languageSelectLayout->addWidget(languageSelectLabel); + languageSelectLayout->addWidget(languageSelect); + languageSelectLayout->addStretch(); + languageSelectLayout->addWidget(languageSelectTip); + + languageMainLayout->addLayout(languageSelectLayout); + + connect(languageSelect, &QComboBox::currentTextChanged, [=](const QString& str) { + _configIn->_translation.setLanguage(str.toStdString()); + languageSelectTip->setText(QString::fromStdString(_config->_translation.translate("will change after restart"))); + }); + + m_layout->addWidget(languageGroupBox); + } + //控制台 + { + // 创建控制台设置分组容器 + QGroupBox* consoleGroupBox = new QGroupBox(QString::fromStdString(_config->_translation.translate("Window Settings"))); + consoleGroupBox->setObjectName("consoleGroupBox"); + consoleGroupBox->setStyleSheet(R"( + QGroupBox#consoleGroupBox { + background: rgb(50, 55, 60); + border-radius: 10px; + font-family: "微软雅黑"; + font-size: 14px; + font-weight: bold; + color: white; + padding-top: 20px; + } + QGroupBox#consoleGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 10px 0 10px; + } + )"); + + QVBoxLayout* consoleMainLayout = new QVBoxLayout(consoleGroupBox); + consoleMainLayout->setContentsMargins(15, 15, 15, 15); + consoleMainLayout->setSpacing(10); + + // 添加说明文字 + QLabel* consoleDescription = new QLabel(QString::fromStdString(_config->_translation.translate("Control the visibility of the debug console window"))); + consoleDescription->setFont(font2); + consoleDescription->setPalette(palette); + consoleDescription->setStyleSheet("color: rgb(180, 180, 180);"); + consoleMainLayout->addWidget(consoleDescription); + + QHBoxLayout* consoletLayout = new QHBoxLayout(); + consoletLayout->setSpacing(15); + + fancyButtonText* showConsoleBtn = new fancyButtonText(QString::fromStdString(_config->_translation.translate("showConsole"))); + showConsoleBtn->setStyleSheet(R"( + fancyButtonText { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(80, 180, 80), stop:1 rgb(60, 140, 60)); + border-radius: 8px; + color: white; + font-weight: bold; + } + fancyButtonText:hover { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(100, 200, 100), stop:1 rgb(80, 160, 80)); + } + )"); + + fancyButtonText* hideConsoleBtn = new fancyButtonText(QString::fromStdString(_config->_translation.translate("hideConsole"))); + hideConsoleBtn->setStyleSheet(R"( + fancyButtonText { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(180, 80, 80), stop:1 rgb(140, 60, 60)); + border-radius: 8px; + color: white; + font-weight: bold; + } + fancyButtonText:hover { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(200, 100, 100), stop:1 rgb(160, 80, 80)); + } + )"); + + fancyButtonText* setResolutionBtn = new fancyButtonText(u8"设置1920x1040"); + setResolutionBtn->setStyleSheet(R"( + fancyButtonText { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(80, 130, 180), stop:1 rgb(60, 100, 140)); + border-radius: 8px; + color: white; + font-weight: bold; + } + fancyButtonText:hover { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgb(100, 150, 200), stop:1 rgb(80, 120, 160)); + } + )"); + + consoletLayout->addWidget(showConsoleBtn); + consoletLayout->addWidget(hideConsoleBtn); + consoletLayout->addWidget(setResolutionBtn); + consoletLayout->addStretch(); + + consoleMainLayout->addLayout(consoletLayout); + + connect(showConsoleBtn, &QPushButton::clicked, [=]() { + ShowWindow(_config->consoleHandle, SW_SHOW); + }); + + connect(hideConsoleBtn, &QPushButton::clicked, [=]() { + ShowWindow(_config->consoleHandle, SW_HIDE); + }); + + connect(setResolutionBtn, &QPushButton::clicked, [=]() { + // 获取当前窗口的顶级窗口 + QWidget* topWidget = this; + while (topWidget->parentWidget()) { + topWidget = topWidget->parentWidget(); + } + + // 设置窗口大小为1920x1040 + topWidget->resize(1920, 1040); + + // 可选:将窗口居中显示 + QScreen* screen = QApplication::primaryScreen(); + if (screen) { + QRect screenGeometry = screen->geometry(); + int x = (screenGeometry.width() - 1920) / 2; + int y = (screenGeometry.height() - 1080) / 2; + topWidget->move(x, y); + } + }); + + m_layout->addWidget(consoleGroupBox); + } + // 硬件信息区域 + { + // 创建硬件信息分组容器 + QGroupBox* hardwareGroupBox = new QGroupBox(QString::fromStdString(_config->_translation.translate("Hardware Information"))); + hardwareGroupBox->setObjectName("hardwareGroupBox"); + hardwareGroupBox->setStyleSheet(R"( + QGroupBox#hardwareGroupBox { + background: rgb(50, 55, 60); + border-radius: 10px; + font-family: "微软雅黑"; + font-size: 14px; + font-weight: bold; + color: white; + padding-top: 20px; + } + QGroupBox#hardwareGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 10px 0 10px; + } + )"); + + QVBoxLayout* hardwareMainLayout = new QVBoxLayout(hardwareGroupBox); + hardwareMainLayout->setContentsMargins(15, 15, 15, 15); + hardwareMainLayout->setSpacing(10); + + // 设置硬件信息组件的样式 + _hardwareInfoWidget.setStyleSheet(R"( + QWidget { + background: transparent; + color: white; + font-family: "微软雅黑"; + } + QLabel { + color: rgb(220, 220, 220); + font-size: 12px; + } + )"); + + hardwareMainLayout->addWidget(&_hardwareInfoWidget); + m_layout->addWidget(hardwareGroupBox); + } + + // 添加底部伸缩空间 + m_layout->addStretch(); + + // 设置滚动区域 + scrollArea->setWidget(contentWidget); + mainLayout->addWidget(scrollArea); + + } +protected: + +private: + appConfig* _config; + hardwareInfoWidget _hardwareInfoWidget; + //std::vector> privateJsondatas;//路径与数据 + //std::vector> privateWidgets;//路径与数据 + //std::vectorjsonLayouts; +}; +#pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/sqlControlWidget.h b/src/launcher/GUI/front/pages/sqlControlWidget.h index 9bade39..f4c0a21 100644 --- a/src/launcher/GUI/front/pages/sqlControlWidget.h +++ b/src/launcher/GUI/front/pages/sqlControlWidget.h @@ -10,8 +10,7 @@ #include #include #include -class sqliteReader : public QWidget -{ +class sqliteReader : public QWidget{ Q_OBJECT public: @@ -30,7 +29,7 @@ public: showLabel->setPalette(palette); vLayout->addWidget(showLabel); - tableSelectComboBox->setFixedWidth(150); + tableSelectComboBox->setFixedWidth(200); vLayout->addWidget(tableSelectComboBox); connect(tableSelectComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=]() { @@ -132,17 +131,16 @@ private: QComboBox* tableSelectComboBox = new QComboBox(); QVBoxLayout* layout = new QVBoxLayout(this); QTableView* tableWidget = new QTableView(); - fancyButtonText* refreshBtn = new fancyButtonText(80, 25, u8"刷新", ""); - fancyButtonText* searchSnBtn = new fancyButtonText(80, 25, u8"查询", ""); - fancyButtonText* dumpToCsvBtn = new fancyButtonText(80, 25, u8"导出", ""); + fancyButtonText* refreshBtn = new fancyButtonText(u8"刷新", 80, 25, ""); + fancyButtonText* searchSnBtn = new fancyButtonText(u8"查询", 80, 25, ""); + fancyButtonText* dumpToCsvBtn = new fancyButtonText(u8"导出", 80, 25, ""); protected: void showEvent(QShowEvent* event) override { QWidget::showEvent(event); refreshTable(); } }; -class sqlControlWidget :public QWidget -{ +class sqlControlWidget :public QWidget{ public: QVBoxLayout* Layout = new QVBoxLayout(this); QHBoxLayout* btnLayout = new QHBoxLayout(this); diff --git a/src/launcher/GUI/mainwindow.cpp b/src/launcher/GUI/mainwindow.cpp index 13b93bf..baa7ca2 100644 --- a/src/launcher/GUI/mainwindow.cpp +++ b/src/launcher/GUI/mainwindow.cpp @@ -8,27 +8,26 @@ #include #include #include -const int topBarHeight = 35; + + MainWindow::MainWindow(appConfig* configIn, qtFuncBridge*bridgeIn, nlohmann::ordered_json& jsonIn) : ui(new Ui::MainWindow), - bridge(bridgeIn), - config(configIn), - json(jsonIn), + bridge(bridgeIn),config(configIn),json(jsonIn), _SummuaryDataPage(configIn,jsonIn["sublUiSetting"]), _loadingWidget(bridgeIn){ + topBar = new topToolBar(this,configIn,this); + leftBar = new leftToolBar(this); + // 将菜单栏添加到MainWindow的布局中 ui->setupUi(this); this->setWindowFlags(Qt::FramelessWindowHint); // 设置无边框的样式 setMouseTracking(true);//鼠标追踪 this->setMinimumSize(1280, 720); this->setMaximumSize(9999, 9999); this->setObjectName("MainWidget"); -#if switchToTongYongUi == 0 - this->setStyleSheet(QString("QWidget#MainWidget {background-color: rgb(%1)}").arg(sColor_Blue)); -#else - this->setStyleSheet(QString("QWidget#MainWidget {background-color: rgb(0,0,0)}")); -#endif - this->setCentralWidget(&stackedWidgets); + this->setStyleSheet(QString("QWidget#MainWidget {background-color: rgb(0,0,0)}")); + this->setCentralWidget(&stackedWidgets); + _loadingWidget.start(); //登录界面 stackedWidgets.addWidget(&_loginWindow); connect(&_loginWindow, &loginWindow::login, this, &MainWindow::login); @@ -39,22 +38,17 @@ MainWindow::MainWindow(appConfig* configIn, qtFuncBridge*bridgeIn, nlohmann::ord //第一层 只有顶部菜单栏和第二层layout mainWidget = new QWidget(); stackedWidgets.addWidget(mainWidget); - mainLayout = new QVBoxLayout(mainWidget); + mainLayout = new QGridLayout(mainWidget); mainLayout->setContentsMargins(0, 0, 0, 0); - topBarInit(); - - //第二层 只有左侧菜单栏和主界面 - mainWidget2 = new QWidget(); - mainLayout2 = new QHBoxLayout(mainWidget2); - mainLayout2->setAlignment(Qt::AlignLeft); - mainLayout2->setContentsMargins(0, 0, 0, 0); - mainLayout->addWidget(mainWidget2); + this->setMenuWidget(topBar); + //mainLayout->addWidget(topBar,0,0); + mainLayout->addWidget(leftBar, 1, 0, 1, 1); leftBarInit(); - mainLayout2->addWidget(&pageWidgets); - - //动画 - blurEffect = new QGraphicsBlurEffect(); + mainLayout->addWidget(&pageWidgets,1,1,1,1); + //mainLayout->setRowStretch(5, 187); + //mainLayout->setColumnStretch(3, 105); + //毛玻璃效果 this->setGraphicsEffect(blurEffect); blurEffectAnimation = new QPropertyAnimation(blurEffect, "blurRadius"); @@ -65,8 +59,7 @@ MainWindow::MainWindow(appConfig* configIn, qtFuncBridge*bridgeIn, nlohmann::ord showMaximized(); QObject::connect(_loadingWidget.manualBtn, &QPushButton::clicked, this, &MainWindow::switchToManulMode); _displayWidget->historyImgs->hide(); - //_displayWidget->rightWidget1->hide(); - //addDashBoardData(0, false); + #if skipLogin == 1 login(true); #endif @@ -76,162 +69,17 @@ MainWindow::~MainWindow(){ } -void MainWindow::topBarInit(){ - int buttonWidth = 50; - QWidget* menuBarWidget = new QWidget();//第一层QWidget - menuBarWidget->setStyleSheet(QString("QWidget { background-color: black;" - "border: 0px solid red;" // 显式设置边框 - "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 - "}")); - menuBarWidget->setFixedHeight(topBarHeight); - QHBoxLayout* layout = new QHBoxLayout(menuBarWidget); - layout->setContentsMargins(0, 0, 0, 0); - mainLayout->addWidget(menuBarWidget); - - QWidget* leftWidget = new QWidget(); - leftWidget->setFixedHeight(topBarHeight); - QHBoxLayout* leftLayout = new QHBoxLayout(leftWidget); - leftLayout->setContentsMargins(0, 0, 0, 0); - leftLayout->setAlignment(Qt::AlignLeft); - - QWidget* midtWidget = new QWidget(); - midtWidget->setFixedHeight(topBarHeight); - QHBoxLayout* midLayout = new QHBoxLayout(midtWidget); - midLayout->setContentsMargins(0, 0, 0, 0); - midLayout->setAlignment(Qt::AlignCenter); - - QWidget* rightWidget = new QWidget(); - rightWidget->setFixedHeight(topBarHeight); - QHBoxLayout* rightLayout = new QHBoxLayout(rightWidget); - rightLayout->setContentsMargins(0, 0, 0, 0); - rightLayout->setAlignment(Qt::AlignRight); - - layout->addWidget(leftWidget); - layout->addWidget(midtWidget); - layout->addWidget(rightWidget); - - // 左侧 - QPalette palette; - palette.setColor(QPalette::WindowText, Qt::white); - QFont font("微软雅黑", 18, QFont::Bold); -#if switchToTongYongUi == false - font.setItalic(true); - QString title(QString::fromStdString(config->softwareTile)); - QLabel* iconLabel = new QLabel(title); - iconLabel->setFont(font); - iconLabel->setScaledContents(true); // 将 pixmap 自动填充 QLabel 的大小 - iconLabel->setFixedHeight(topBarHeight); - leftLayout->addWidget(iconLabel); - iconLabel->setFixedWidth(buttonWidth); - iconLabel->setFixedWidth((buttonWidth/2)* title.size()); - iconLabel->setPalette(palette); -#else - QLabel* factoryIconLabel = new QLabel(); - factoryIconLabel->setPixmap(QPixmap(":/icon/icon/logo_Dongsheng.png")); // 设置图标 - factoryIconLabel->setScaledContents(true); // 将 pixmap 自动填充 QLabel 的大小 - factoryIconLabel->setFixedSize(topBarHeight, topBarHeight); - leftLayout->addWidget(factoryIconLabel); - - QString title(QString::fromStdString("AI检测系统")); - QLabel* titleLabel = new QLabel(title); - titleLabel->setFont(font); - titleLabel->setScaledContents(true); // 将 pixmap 自动填充 QLabel 的大小 - titleLabel->setFixedHeight(topBarHeight); - midLayout->addWidget(titleLabel); - titleLabel->setFixedWidth(buttonWidth); - titleLabel->setFixedWidth((buttonWidth / 2) * title.size()); - titleLabel->setPalette(palette); -#endif - // 右侧 - //最小化 - QPushButton* minimizeButton = new QPushButton(); - minimizeButton->setIcon(QPixmap(":/icon/icon/minus.png")); // 设置图标 - minimizeButton->setStyleSheet(QString("QPushButton { background-color: transparent;" - "border: 0px solid red;" // 显式设置边框 - "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 - "}" - "QPushButton:focus {" - " outline: none;" - "}" - "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_Gold)); // 设置透明背景和悬停时的背景色 - minimizeButton->setFixedHeight(topBarHeight); - minimizeButton->setFixedWidth(buttonWidth); - QObject::connect(minimizeButton, &QPushButton::clicked, this, &MainWindow::minimizeWindow); // 点击最小化按钮 - rightLayout->addWidget(minimizeButton); - - //最大化与缩小 - maximizeRestoreButton = new QPushButton(); - maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen.png")); // 设置图标 - maximizeRestoreButton->setStyleSheet(QString("QPushButton { background-color: transparent;" - "border: 0px solid red;" // 显式设置边框 - "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 - "}" - "QPushButton:focus {" - " outline: none;" - "}" - "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_Gold)); // 设置透明背景和悬停时的背景色 - maximizeRestoreButton->setFixedHeight(topBarHeight); - maximizeRestoreButton->setFixedWidth(buttonWidth); - //QObject::connect(maximizeRestoreButton, &QPushButton::clicked, this, &MainWindow::toggleMaximize); // 点击最大化/还原按钮 - QObject::connect(maximizeRestoreButton, &QPushButton::clicked, this, [=]() {toggleMaximize(reverse); }); // 点击最大化/还原按钮 - rightLayout->addWidget(maximizeRestoreButton); - - //关闭窗口 - QPushButton* exitButton = new QPushButton(); - exitButton->setIcon(QPixmap(":/icon/icon/close.png")); // 设置图标 - rightLayout->addWidget(exitButton); - exitButton->setFixedHeight(topBarHeight); - exitButton->setStyleSheet(QString("QPushButton { background-color: transparent;" - "border: 0px solid red;" // 显式设置边框 - "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 - "}" - "QPushButton:focus {" - " outline: none;" - "}" - "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_Red)); // 设置透明背景和悬停时的背景色 - exitButton->setFixedHeight(topBarHeight); - exitButton->setFixedWidth(buttonWidth); - QObject::connect(exitButton, &QPushButton::clicked, this, &MainWindow::QuitCheck); // 点击退出按钮退出应用程序 - // 将菜单栏添加到MainWindow的布局中 - this->setMenuWidget(menuBarWidget); - _loadingWidget.start(); - -} -void MainWindow::QuitCheck() { - //跳出确认窗口 - QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "退出确认", "您确定要退出吗?", - QMessageBox::Yes | QMessageBox::No); - if (reply == QMessageBox::Yes) { - Quit(); // 确认退出 - } - else { - // 取消退出 - qDebug() << "用户取消了退出操作"; - } -} -void MainWindow::Quit() { - config->saveSettingJson(); - qDebug() << "退出应用程序"; - QApplication::quit(); // 退出应用程序 -} void MainWindow::leftBarInit() { - int defaultWidth = 50; - int defaultHeight = 50; + - QWidget* leftBarWidget = new QWidget(); - leftBarWidget->setFixedWidth(defaultHeight); - leftBarWidget->setStyleSheet(QString("QWidget { background-color: black;" - "border: 0px solid red;" // 显式设置边框 - "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 - "}")); - QVBoxLayout* leftBarLayout = new QVBoxLayout(leftBarWidget); - leftBarLayout->setContentsMargins(0, 0, 0, 0); - mainLayout2->addWidget(leftBarWidget); - leftBarWidget->setFixedWidth(defaultWidth); - leftBarLayout->setAlignment(Qt::AlignTop); + //QWidget* leftBarWidget = new QWidget(); + //leftBarWidget->setFixedWidth(defaultHeight); + + + + //leftBarWidget->setFixedWidth(defaultWidth); //主页面 _displayWidget = new displayWidget(config); @@ -256,23 +104,11 @@ void MainWindow::leftBarInit() { _sqlControlWidget = new sqlControlWidget(config); registerPageBar(":/icon/icon/sql.png", u8"数据库", _sqlControlWidget); - //PLUGIN - //registerPageBar(":/icon/icon/sql.png", u8"SQL可视化", _pluginManagerWidget); // //配置页面 - _configSettingWidget = new configSettingWidget(config); - registerPageBar(":/icon/icon/setting.png", u8"配置设置", _configSettingWidget); - - for (int index = 0; index < pageBtns.size(); index++) { - if(index == pageBtns.size() -1) - leftBarLayout->addStretch(); - leftBarLayout->addWidget(pageBtns[index]); - connect(pageBtns[index], &QPushButton::clicked, [=]() { - switchStackWidget(index); - }); - } + _settingWidget = new settingWidget(config); + registerPageBar(":/icon/icon/setting.png", u8"配置设置", _settingWidget); - pageBtns[0]->click(); + leftBar->pageBtns[0]->click(); QObject::connect(_displayWidget, &displayWidget::changeStackWidget, this, &MainWindow::switchStackWidget); -// QObject::connect(_displayWidget, &displayWidget::historyClickSignal, _historyWidget, &historyWidget::widgetJumpWithPath); } \ No newline at end of file diff --git a/src/launcher/GUI/mainwindow.h b/src/launcher/GUI/mainwindow.h index 32c8aa8..3afa0f2 100644 --- a/src/launcher/GUI/mainwindow.h +++ b/src/launcher/GUI/mainwindow.h @@ -20,7 +20,7 @@ #include "front/loadingWidget.h" #include "front/pages/displayPageWidget.h" -#include "front/pages/configSettingWidget.h" +#include "front/pages/settingWidget.h" #include "front/pages/logPageWidget.h" #include "front/pages/sqlControlWidget.h" #include "front/pages/manualDetWidget.h" @@ -29,7 +29,7 @@ #include "front/pages/pluginManagerWidget.hpp" #include "front/pages/summary_data_page.h" #include -#include 8 +#include #pragma execution_character_set("utf-8") QT_BEGIN_NAMESPACE @@ -37,17 +37,217 @@ namespace Ui { class MainWindow; } QT_END_NAMESPACE class fbBridge; class appConfig; +class topToolBar : public QWidget { + Q_OBJECT +public: + enum toggleMaximizeEnum { + reverse, + normal, + max + }; + const int topBarHeight = 40; + const int buttonWidth = 50; + topToolBar(QMainWindow* mainWindowIN,appConfig* configIN = nullptr,QWidget* parent = nullptr) + : QWidget(parent), config(configIN), mainWindow(mainWindowIN){ + + this->setStyleSheet(QString("QWidget { background-color: black;" + "border: 0px solid red;" // 显式设置边框 + "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 + "}")); + this->setFixedHeight(topBarHeight); + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + //mainLayout->addWidget(menuBarWidget); + + QWidget* leftWidget = new QWidget(); + leftWidget->setFixedHeight(topBarHeight); + QHBoxLayout* leftLayout = new QHBoxLayout(leftWidget); + leftLayout->setContentsMargins(0, 0, 0, 0); + leftLayout->setAlignment(Qt::AlignLeft); + + QWidget* midtWidget = new QWidget(); + midtWidget->setFixedHeight(topBarHeight); + QHBoxLayout* midLayout = new QHBoxLayout(midtWidget); + midLayout->setContentsMargins(0, 0, 0, 0); + midLayout->setAlignment(Qt::AlignCenter); + + QWidget* rightWidget = new QWidget(); + rightWidget->setFixedHeight(topBarHeight); + QHBoxLayout* rightLayout = new QHBoxLayout(rightWidget); + rightLayout->setContentsMargins(0, 0, 0, 0); + rightLayout->setAlignment(Qt::AlignRight); + + layout->addWidget(leftWidget); + layout->addWidget(midtWidget); + layout->addWidget(rightWidget); + + // 左侧 + QPalette palette; + palette.setColor(QPalette::WindowText, Qt::white); + QFont font("微软雅黑", 18, QFont::Bold); + + QLabel* factoryIconLabel = new QLabel(); + factoryIconLabel->setPixmap(QPixmap(":/icon/icon/logo_Dongsheng.png")); // 设置图标 + factoryIconLabel->setScaledContents(true); // 将 pixmap 自动填充 QLabel 的大小 + factoryIconLabel->setFixedSize(topBarHeight, topBarHeight); + leftLayout->addWidget(factoryIconLabel); + + QString title(QString::fromStdString(config->_translation.translate("AI-DetectionSystem"))); + QLabel* titleLabel = new QLabel(title); + titleLabel->setFont(font); + titleLabel->setPalette(palette); + titleLabel->setScaledContents(true); // 将 pixmap 自动填充 QLabel 的大小 + titleLabel->setFixedHeight(topBarHeight); + midLayout->addWidget(titleLabel); + + // 右侧 + //最小化 + QPushButton* minimizeButton = new QPushButton(); + minimizeButton->setIcon(QPixmap(":/icon/icon/minus.png")); // 设置图标 + minimizeButton->setStyleSheet(QString("QPushButton { background-color: transparent;" + "border: 0px solid red;" // 显式设置边框 + "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 + "}" + "QPushButton:focus {" + " outline: none;" + "}" + "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_Gold)); // 设置透明背景和悬停时的背景色 + minimizeButton->setFixedHeight(topBarHeight); + minimizeButton->setFixedWidth(buttonWidth); + QObject::connect(minimizeButton, &QPushButton::clicked, this, [=]() {mainWindow->showMinimized(); }); // 点击最小化按钮 + rightLayout->addWidget(minimizeButton); + + //最大化与缩小 + maximizeRestoreButton = new QPushButton(); + maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen.png")); // 设置图标 + maximizeRestoreButton->setStyleSheet(QString("QPushButton { background-color: transparent;" + "border: 0px solid red;" // 显式设置边框 + "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 + "}" + "QPushButton:focus {" + " outline: none;" + "}" + "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_Gold)); // 设置透明背景和悬停时的背景色 + maximizeRestoreButton->setFixedHeight(topBarHeight); + maximizeRestoreButton->setFixedWidth(buttonWidth); + //QObject::connect(maximizeRestoreButton, &QPushButton::clicked, this, &MainWindow::toggleMaximize); // 点击最大化/还原按钮 + QObject::connect(maximizeRestoreButton, &QPushButton::clicked, this, [=]() {toggleMaximize(reverse); }); // 点击最大化/还原按钮 + rightLayout->addWidget(maximizeRestoreButton); + + //关闭窗口 + QPushButton* exitButton = new QPushButton(); + exitButton->setIcon(QPixmap(":/icon/icon/close.png")); // 设置图标 + rightLayout->addWidget(exitButton); + exitButton->setFixedHeight(topBarHeight); + exitButton->setStyleSheet(QString("QPushButton { background-color: transparent;" + "border: 0px solid red;" // 显式设置边框 + "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 + "}" + "QPushButton:focus {" + " outline: none;" + "}" + "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_Red)); // 设置透明背景和悬停时的背景色 + exitButton->setFixedHeight(topBarHeight); + exitButton->setFixedWidth(buttonWidth); + QObject::connect(exitButton, &QPushButton::clicked, this, &topToolBar::QuitCheck); // 点击退出按钮退出应用程序 + } +public slots: + void toggleMaximize(toggleMaximizeEnum toggleMaximizeEnumIn = reverse) { + switch (toggleMaximizeEnumIn) { + case reverse: + if (mainWindow->isMaximized()) { + mainWindow->showNormal(); + maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen.png")); + } + else { + mainWindow->showMaximized(); + maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen-exit.png")); + } + break; + case normal: + mainWindow->showNormal(); + maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen.png")); + break; + case max: + mainWindow->showMaximized(); + maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen-exit.png")); + break; + } + } + void QuitCheck() { + //跳出确认窗口 + QMessageBox::StandardButton reply; + reply = QMessageBox::question(mainWindow, + QString::fromStdString(config->_translation.translate("Exit Confirmation")), + QString::fromStdString(config->_translation.translate("Do you want to exit the application?")), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + Quit(); // 确认退出 + } + else { + // 取消退出 + qDebug() << "用户取消了退出操作"; + } + } + void Quit() { + config->saveSettingJson(); + qDebug() << "退出应用程序"; + QApplication::quit(); // 退出应用程序 + } +private: + QMainWindow* mainWindow; + QPushButton* maximizeRestoreButton; + appConfig* config; +}; +class leftToolBar : public QWidget { +public: + leftToolBar(QWidget* parent = nullptr) : QWidget(parent) { + //int defaultWidth = 50; + //int defaultHeight = 50; + this->setStyleSheet(QString("QWidget { background-color: black;" + "border: 0px solid red;" // 显式设置边框 + "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 + "}")); + + Layout->setContentsMargins(0, 0, 0, 0); + Layout->setAlignment(Qt::AlignTop); + } + ~leftToolBar() { + for(auto btn: pageBtns) + delete btn; + pageBtns.clear(); + } +#pragma region 窗口切换栏 + QSize& m_pageBarSize = QSize(50, 50); + toolBarButton* registerPageBar(QString iconPath, QString pageDescription, QWidget* page) { + toolBarButton* toMainBtn = new toolBarButton( + m_pageBarSize.width(), + m_pageBarSize.height(), + QIcon(iconPath), + pageBtns.size(), + pageDescription); + //pageWidgets.addWidget(page); + pageBtns.push_back(toMainBtn); + Layout->addWidget(toMainBtn); + return toMainBtn; + //如果报错请检查Qwidget是否有效 + } +#pragma endregion + std::vectorpageBtns; + QVBoxLayout* Layout = new QVBoxLayout(this); +}; class MainWindow : public QMainWindow{ Q_OBJECT public: + topToolBar* topBar;//顶部栏 + leftToolBar* leftBar;//左侧栏 MainWindow(appConfig* config = nullptr, qtFuncBridge* bridge = nullptr, nlohmann::ordered_json& _jsonIn = nlohmann::ordered_json()); ~MainWindow(); //主要控件 - std::vectorpageBtns; QStackedWidget stackedWidgets;//一共三层,加载界面,登录界面,主要界面 QStackedWidget pageWidgets;//主要界面中的页面 loginWindow _loginWindow;//登录界面 @@ -55,7 +255,7 @@ public: //页面 displayWidget* _displayWidget; - configSettingWidget* _configSettingWidget; + settingWidget* _settingWidget; logWidget* _logWidget; sqlControlWidget* _sqlControlWidget; manualDetWidget* _manualDetWidget; @@ -68,22 +268,14 @@ private: appConfig* config; nlohmann::ordered_json json; //动画效果 - QGraphicsBlurEffect* blurEffect; + QGraphicsBlurEffect* blurEffect = new QGraphicsBlurEffect(); QPropertyAnimation* blurEffectAnimation; - - QPushButton* maximizeRestoreButton; - - QVBoxLayout* mainLayout; - QHBoxLayout* mainLayout2; + QGridLayout* mainLayout; QWidget* mainWidget; - QWidget* mainWidget2; bool isLogin = false; bool backEndInit = false; - - void topBarInit(); void leftBarInit(); - void QuitCheck(); //窗口移动 #pragma region 窗口移动变量 bool isMoving = false; @@ -92,88 +284,39 @@ private: QTime lastWindowMoveTime; int freshDelay = 1000 / windowMoveFreshRate; bool setNormalAndMove = false;//判断是否从最大化开始移动 -#pragma endregion - //窗口缩放 -#pragma region 窗口缩放变量 - enum toggleMaximizeEnum - { - reverse, - normal, - max - }; #pragma endregion #pragma region 窗口切换栏 - QSize& m_pageBarSize = QSize(50, 50); - void registerPageBar(QString iconPath, QString pageDescription,QWidget* page) { - toolBarButton* toMainBtn = new toolBarButton( - m_pageBarSize.width(), - m_pageBarSize.height(), - QIcon(iconPath), - pageDescription); + void registerPageBar(QString iconPath, QString pageDescription, QWidget* page) { + auto btn = leftBar->registerPageBar(iconPath, pageDescription, page); + connect(btn, &toolBarButton::toolBarButtonClicked, [=](int index) { + switchStackWidget(index); + }); pageWidgets.addWidget(page); - pageBtns.push_back(toMainBtn); //如果报错请检查Qwidget是否有效 } #pragma endregion public slots: - void Quit(); - void switchToManulMode() - { + void switchToManulMode(){ _displayWidget->setDisabled(true); loading(false); } - void minimizeWindow() - { - showMinimized(); - } - void switchStackWidget(int index) - { - for (int index2 = 0; index2 < pageBtns.size(); index2++) - { + void switchStackWidget(int index){ + for (int index2 = 0; index2 < leftBar->pageBtns.size(); index2++){ if (index2 != index) - pageBtns[index2]->toDefault(); + leftBar->pageBtns[index2]->toDefault(); } - pageBtns[index]->pressed(); + leftBar->pageBtns[index]->pressed(); pageWidgets.setCurrentIndex(index); qDebug() << "switch Page to Index:" << index; } - void toggleMaximize(toggleMaximizeEnum toggleMaximizeEnumIn = reverse) - { - switch (toggleMaximizeEnumIn) - { - case reverse: - if (isMaximized()) { - showNormal(); - maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen.png")); - } - else { - showMaximized(); - maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen-exit.png")); - } - break; - case normal: - showNormal(); - maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen.png")); - break; - case max: - showMaximized(); - maximizeRestoreButton->setIcon(QPixmap(":/icon/icon/fullscreen-exit.png")); - break; - } - - _displayWidget->windowChanged(); - } - void switchstackedWidgets(int index) - { + + void switchstackedWidgets(int index){ stackedWidgets.setCurrentIndex(index); } - void login(bool input) - { - if (input == true) - { + void login(bool input){ + if (input == true){ #if disableBackEndCheck == 0 - if (backEndInit == false) - { + if (backEndInit == false){ isLogin = true; loading(true); } @@ -189,16 +332,13 @@ public slots: blurEffectAnimation->start(); } } - else if (input == false) - { + else if (input == false){ stackedWidgets.setCurrentIndex(0); loading(false); } } - void loading(bool input) - { - if (input == true) - { + void loading(bool input){ + if (input == true){ blurEffectAnimation->setStartValue(0); blurEffectAnimation->setEndValue(20); @@ -209,8 +349,7 @@ public slots: blurEffectAnimation->start(); } - else if (input == false) - { + else if (input == false){ blurEffectAnimation->setStartValue(0); blurEffectAnimation->setEndValue(0); blurEffectAnimation->start(); @@ -221,17 +360,13 @@ public slots: blurEffectAnimation->start(); } } - void recvPixmapImageWidget(showImgPack pack) - { + void recvPixmapImageWidget(showImgPack pack){ if (pack.type != nullptr) { _displayWidget->_ImageWidgetManager.showImg(pack.img, pack.name, pack.type); } - } - void recvInitFinished(initStatus input) - { - switch (input) - { + void recvInitFinished(initStatus input){ + switch (input){ case initStatus::InitOK: backEndInit = true; if (isLogin == true) @@ -242,28 +377,15 @@ public slots: backEndInit = false; } } - void recvInitString(QString strIn) - { - if (_loadingWidget.isRunning != false) - { + void recvInitString(QString strIn){ + if (_loadingWidget.isRunning != false){ _loadingWidget.initLog->append(strIn); } } - void addDetHistoryData(bool isOK, historyPack _historyPack) - { + void addDetHistoryData(bool isOK, historyPack _historyPack){ _displayWidget->historyImgs->addData(isOK, _historyPack); } - //void addDashBoardData(int index, bool value)//增加一个OK/NG数据到dashboard - //{ - // if (_displayWidget->_summaryDataManager->dashBoardWidgets.size() - 1 < index) - // qDebug() << __LINE__ << "index out of Size"; - // if(value==true) - // _displayWidget->_summaryDataManager->dashBoardWidgets[index]->addOk(); - // else - // _displayWidget->_summaryDataManager->dashBoardWidgets[index]->addNG(); - //} - void addCtData(int index, int value) - { + void addCtData(int index, int value){ switch (index) { case 0: @@ -274,9 +396,6 @@ public slots: break; } } - //void resetDashBoard();//reset dashBoard - //void addShowPerformanceWidgetData(int index, int timeCost); - //void resetShowPerformanceWidget(); void slot_summaryData_addData(QString window, double data) { _SummuaryDataPage.addData(window, data); } @@ -285,15 +404,14 @@ signals: void recvPixmapImageWidgetSignal(showImgPack*); void signal_summaryData_addData(QString window, double data); protected: - void mouseDoubleClickEvent(QMouseEvent* event) override - { - if (event->pos().y() < 35) + void mouseDoubleClickEvent(QMouseEvent* event) override { + if (event->pos().y() < topBar->topBarHeight) return - toggleMaximize(reverse); + topBar->toggleMaximize(); QMainWindow::mouseDoubleClickEvent(event); } void mousePressEvent(QMouseEvent* event) override { - if (event->pos().y() > 35) + if (event->pos().y() > topBar->topBarHeight) return; if (event->button() == Qt::LeftButton) { startPos = event->globalPos(); @@ -323,6 +441,7 @@ protected: } void resizeEvent(QResizeEvent* event) override { QMainWindow::resizeEvent(event); + _displayWidget->windowChanged(); } }; #endif // MAINWINDOW_H diff --git a/src/launcher/GUI/uiModule/components/enterPasswdWindow.h b/src/launcher/GUI/uiModule/components/enterPasswdWindow.h index 22125a5..4783f0f 100644 --- a/src/launcher/GUI/uiModule/components/enterPasswdWindow.h +++ b/src/launcher/GUI/uiModule/components/enterPasswdWindow.h @@ -6,8 +6,7 @@ #include #include "fancyDialog.h" #include"fancyButton.h" -class enterPasswdWindow : public fancyDialog -{ +class enterPasswdWindow : public fancyDialog{ Q_OBJECT public : std::string passwd = "EXE"; @@ -15,8 +14,7 @@ public : fancyButtonText okBtn; enterPasswdWindow(): fancyDialog("请输入密码","",false), - okBtn(120,60,"确认","确认") - { + okBtn("确认", 120, 60, "确认"){ init(); QFont font2("微软雅黑", 18, QFont::Bold);; this->funcBtnLayout->addWidget(&passwordLine); @@ -26,8 +24,7 @@ public : this->funcBtnLayout->addLayout(btnLayout); QObject::connect(&okBtn, &QPushButton::clicked, this, [=]() {verifyPasswd(passwordLine.text().toStdString()); }); } - void init() - { + void init(){ passwordLine.clear(); this->detailLabel->setText(""); } diff --git a/src/launcher/GUI/uiModule/components/fancyButton.h b/src/launcher/GUI/uiModule/components/fancyButton.h index 58fd0c0..86acf02 100644 --- a/src/launcher/GUI/uiModule/components/fancyButton.h +++ b/src/launcher/GUI/uiModule/components/fancyButton.h @@ -7,8 +7,7 @@ class fancyButton : public QPushButton { public: QIcon defaultIcon; - fancyButton(int Width, int Height, QIcon defaultIn,QString tips="") - { + fancyButton(int Width, int Height, QIcon defaultIn,QString tips=""){ defaultIcon = defaultIn; this->setToolTip(tips); this->setIcon(defaultIcon); // 设置图标 @@ -16,8 +15,7 @@ public: this->setFixedWidth(Width); toDefault(); } - void toDefault() - { + void toDefault(){ this->setStyleSheet(QString("QPushButton { background-color: transparent;" "border: 0px solid red;" "border-radius: 0px;" @@ -33,8 +31,7 @@ public: class fancyButtonText : public QPushButton { public: QString text; - fancyButtonText(int Width, int Height, QString textIn, QString tips = "") - { + fancyButtonText(QString textIn, int Width = 0, int Height = 0, QString tips = ""){ QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); QFont font("微软雅黑", 14, QFont::Bold); @@ -42,12 +39,12 @@ public: text = textIn; this->setToolTip(tips); this->setText(text); - if (Height != -1) + if (Height != 0) this->setFixedHeight(Height); else this->setMaximumHeight(9999); - if (Width != -1) + if (Width != 0) this->setFixedWidth(Width); else this->setMaximumHeight(9999); @@ -55,8 +52,7 @@ public: this->setFont(font); toDefault(); } - void toDefault() - { + void toDefault(){ this->setStyleSheet(QString("QPushButton { background-color: transparent;" "color: white;" "border: 0px solid red;" @@ -68,8 +64,7 @@ public: "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_GoldWithBlack)); } - void toRed() - { + void toRed(){ this->setStyleSheet(QString("QPushButton { background-color: rgb(%1);" "color: white;" "border: 0px solid red;" @@ -80,8 +75,7 @@ public: "}" "QPushButton:hover { background-color: rgb(%2); }").arg(sColor_Red).arg(sColor_RedWithWhite)); } - void toGreen() - { + void toGreen(){ this->setStyleSheet(QString("QPushButton { background-color: rgb(%1);" "color: white;" "border: 0px solid red;" @@ -96,8 +90,7 @@ public: class gradientButton : public QPushButton { public: QString text; - gradientButton(int Width, int Height, QString textIn, QString tips = "") - { + gradientButton(int Width, int Height, QString textIn, QString tips = ""){ QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); QFont font("微软雅黑", 14, QFont::Bold); @@ -111,8 +104,7 @@ public: this->setFont(font); toDefault(); } - void toDefault() - { + void toDefault(){ this->setStyleSheet( QString("QPushButton {" " color: white;" @@ -140,8 +132,7 @@ public: "}" ).arg(sColor_Gold)); } - void pressed() - { + void pressed(){ this->setStyleSheet( QString("QPushButton {" " color: white;" diff --git a/src/launcher/GUI/uiModule/components/toolBarButton.h b/src/launcher/GUI/uiModule/components/toolBarButton.h index c935c71..3f1525f 100644 --- a/src/launcher/GUI/uiModule/components/toolBarButton.h +++ b/src/launcher/GUI/uiModule/components/toolBarButton.h @@ -5,19 +5,22 @@ #include #include class toolBarButton : public QPushButton { + Q_OBJECT public: QIcon defaultIcon; - toolBarButton(int Width, int Height, QIcon defaultIn,QString tips="") - { + toolBarButton(int Width, int Height, QIcon defaultIn,int indexIN,QString tips=""){ defaultIcon = defaultIn; + index = indexIN; this->setToolTip(tips); this->setIcon(defaultIcon); // 设置图标 this->setFixedHeight(Height); this->setFixedWidth(Width); + + QObject::connect(this, &QPushButton::clicked, this, &toolBarButton::onClicked); toDefault(); } - void toDefault() - { + + void toDefault(){ this->setStyleSheet(QString("QPushButton { background-color: transparent;" "border: 0px solid red;" // 显式设置边框 "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 @@ -25,13 +28,20 @@ public: "QPushButton:hover { background-color: rgb(%1); }").arg(sColor_BlackWithWhite)); } - void pressed() - { + void pressed(){ this->setStyleSheet(QString("QPushButton { background-color:rgb(%1) ;" "border: 0px solid red;" // 显式设置边框 "border-radius: 0px;" // 设置边框半径为0,确保没有圆角 "}" "QPushButton:hover { background-color: rgb(%2); }").arg(sColor_GoldWithBlack).arg(sColor_Gold)); // 设置透明背景和悬停时的背景色 } +private: + int index = 0; +private slots: + void onClicked(){ + emit toolBarButtonClicked(index); + } +signals: + void toolBarButtonClicked(int index); }; #pragma once \ No newline at end of file diff --git a/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h b/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h index 50ecfa3..3178463 100644 --- a/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h +++ b/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h @@ -8,8 +8,7 @@ #include #include #include -class _952BiaoDingSwitch : public QWidget -{ +class _952BiaoDingSwitch : public QWidget{ Q_OBJECT public: QLabel CurrentModeLabel; @@ -22,12 +21,11 @@ public: QLabel _3dSignLabel, _2dSignLabel, _3dThresholdLabel; enterPasswdWindow _enterPasswdWindow;//密码窗口 _952BiaoDingSwitch() - : NormalBtn(180, 30, "一般模式", "一般模式") - , BiaoDingBtn(180, 30, "标定模式", "标定模式") + : NormalBtn("一般模式", 180, 30, "一般模式") + , BiaoDingBtn("标定模式", 180, 30, "标定模式") , mainLayout(this) - , SaveBtn(180, 30, "保存&应用", "保存&应用") - , RestoreBtn(180, 30, "还原", "还原") - { + , SaveBtn("保存&应用", 180, 30, "保存&应用") + , RestoreBtn("还原", 180, 30, "还原"){ QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); @@ -46,14 +44,12 @@ public: mainLayout.addLayout(btnLayout, 1, 0); //按钮互斥 NormalBtn.toGreen(); - QObject::connect(&NormalBtn, &QPushButton::clicked, this, [=]() - { + QObject::connect(&NormalBtn, &QPushButton::clicked, this, [=]() { NormalBtn.toGreen(); BiaoDingBtn.toDefault(); switchToNormal(); }); - QObject::connect(&BiaoDingBtn, &QPushButton::clicked, this, [=]() - { + QObject::connect(&BiaoDingBtn, &QPushButton::clicked, this, [=]() { BiaoDingBtn.toGreen(); NormalBtn.toDefault(); switchToBiaoDing(); @@ -151,27 +147,23 @@ public: //_core._appConfig.__952BiaoDingSwitchData.in_InnerOffset = JsonInnerOffset; //_core._appConfig.__952BiaoDingSwitchData._3d_threshold = Json3dThreshold; } - catch (...) - { + catch (...){ std::cout << "err load json@_952BiaoDingSwitchConfig" << std::endl; } }; - void switchToBiaoDing() - { + void switchToBiaoDing(){ //QMutexLocker locker(&_core._appConfig.__952BiaoDingSwitchData.mutex); //_core._appConfig.__952BiaoDingSwitchData.modeIn = 1; //JsonObj["mode"] = 1; //saveJsonFromPath("./config/_952BiaoDingSwitchConfig.json", JsonObj); } - void switchToNormal() - { + void switchToNormal(){ //QMutexLocker locker(&_core._appConfig.__952BiaoDingSwitchData.mutex); //_core._appConfig.__952BiaoDingSwitchData.modeIn = 0; //JsonObj["mode"] = 0; //saveJsonFromPath("./config/_952BiaoDingSwitchConfig.json", JsonObj); } - void saveConfig() - { + void saveConfig(){ //QMutexLocker locker(&_core._appConfig.__952BiaoDingSwitchData.mutex); //_core._appConfig.__952BiaoDingSwitchData.in_OutOffset = OutDoubleSpinBox->value(); //_core._appConfig.__952BiaoDingSwitchData.in_InnerOffset = InnerDoubleSpinBox->value(); @@ -183,8 +175,7 @@ public: //qDebug() << "_952BiaoDingSwitch-ValueChanged:in_OutOffset->" << _core._appConfig.__952BiaoDingSwitchData.in_OutOffset // << " | in_InnerOffset->" << _core._appConfig.__952BiaoDingSwitchData.in_InnerOffset; } - void restore() - { + void restore(){ //QMutexLocker locker(&_core._appConfig.__952BiaoDingSwitchData.mutex); //OutDoubleSpinBox->setValue(_core._appConfig.__952BiaoDingSwitchData.in_OutOffset); //InnerDoubleSpinBox->setValue(_core._appConfig.__952BiaoDingSwitchData.in_InnerOffset); diff --git a/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h b/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h index 120e7b0..30be376 100644 --- a/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h +++ b/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h @@ -146,7 +146,7 @@ public: }; class ConnectionWidget : public QWidget { public: - QVBoxLayout* layout = new QVBoxLayout(this); + QHBoxLayout* layout = new QHBoxLayout(this); stateLabel* lanConnectonLabel = new stateLabel(":/icon/icon/lan_connection_ok.png", ":/icon/icon/lan_connection_error.png",this); stateLabel* camConnectonLabel = new stateLabel(":/icon/icon/cam_connection_ok.png", ":/icon/icon/cam_connection_error.png", this); QPixmap lanConnectionOk, lanConnectionError, camConnectionOK, camConnectionError; diff --git a/src/launcher/GUI/uiModule/uiModule_runCommand.h b/src/launcher/GUI/uiModule/uiModule_runCommand.h index 030b158..fd9d36b 100644 --- a/src/launcher/GUI/uiModule/uiModule_runCommand.h +++ b/src/launcher/GUI/uiModule/uiModule_runCommand.h @@ -30,7 +30,7 @@ public slots: QListWidgetItem* item = new QListWidgetItem(btnWidgets); item->setSizeHint(QSize(sizeX - 30, 30)); btnWidgets->addItem(item); - fancyButtonText* funcBtn = new fancyButtonText(sizeX - 30, 30, btnName, tip); + fancyButtonText* funcBtn = new fancyButtonText(btnName, sizeX - 30, 30, tip); btnWidgets->setItemWidget(item, funcBtn); connect(funcBtn, &fancyButtonText::clicked, this, [this, uuid]() { QMessageBox::StandardButton reply; diff --git a/src/launcher/appConfig/appConfig.h b/src/launcher/appConfig/appConfig.h index 54ae27d..41c9080 100644 --- a/src/launcher/appConfig/appConfig.h +++ b/src/launcher/appConfig/appConfig.h @@ -3,31 +3,38 @@ #include #include #include -class appConfig -{ +#include +#include +class appConfig{ public: void parsingSettingJson(); - //sqlManager _sqlManager;//储存产品信息用 - appConfig() { + //sqlManager _sqlManager;//储存产品信息用 + void loadSetting() { parsingSettingJson(); - //_sqlManager.initialization(this); - } + if (_translation.loadFromFile("./config/translation.json")) { + // 当前语言会自动从JSON中的current_language字段读取 + std::cout << "当前语言/Current language: " << _translation.getCurrentLanguage() << std::endl; + } + } void saveSettingJson() { saveJsonFromPath("./config/setting.json", originJson); saveOrderedJsonFromPath("./config/"+ objectSelect +".json", settingJson); + _translation.saveToFile("./config/translation.json"); } std::string settingJsonPath; nlohmann::ordered_json settingJson; - std::string softwareTile;//软件标题 std::string imgSavePath;//原图存储路径 HWND consoleHandle; SQLiteDB* dataBase = nullptr; std::vector< viewerStruct>viewDatas; - //appExternalConfig _appExternalConfig; + Translation _translation; + Auth::UserManager Authorization; private: nlohmann::json originJson; std::string jsonVersion; std::string objectSelect; std::string loginPassWord; + std::string softwareTile;//软件标题 + }; #pragma once \ No newline at end of file diff --git a/src/launcher/appCore.hpp b/src/launcher/appCore.hpp index cc3a56f..06dad2a 100644 --- a/src/launcher/appCore.hpp +++ b/src/launcher/appCore.hpp @@ -8,7 +8,6 @@ // #include "interface.h" #include - #define HIDE_CONSOLE 1 class backEnd { @@ -52,16 +51,18 @@ private: class appCore : public QObject{ Q_OBJECT public: - logService _logService; appConfig _appConfig; backEnd backend; - appCore(){ - - } + logService* _logService = logService::getInstance(); + // 获取日志服务实例 + ~appCore(){ if(_appConfig.dataBase) delete _appConfig.dataBase; //backend.releaseCore(); } + void initConfig() { + _appConfig.loadSetting(); + } void initDatabase(){ _appConfig.dataBase = new SQLiteDB(globalDatabasePth); } diff --git a/src/launcher/hardwareInfo/hardwareInfo.h b/src/launcher/hardwareInfo/hardwareInfo.h index 55e5308..a48320b 100644 --- a/src/launcher/hardwareInfo/hardwareInfo.h +++ b/src/launcher/hardwareInfo/hardwareInfo.h @@ -11,6 +11,7 @@ #include #include +#include static QProcess* process = nullptr; static HANDLE jobHandle = nullptr; @@ -22,7 +23,7 @@ public: const auto cpus = hwinfo::getAllCPUs(); std::vector threads_utility = cpus[0].threadsUtilisation(); cpuMaxThreadsUtilityRecord = std::vector(threads_utility.size(), 0); - test(); + //test(); } double getAvgCpuUseage() { const auto cpus = hwinfo::getAllCPUs(); @@ -244,9 +245,13 @@ class hardwareInfoThread : public QThread { public: int retryCnt = 0, retryMax = 10; hardwareInfoThread() { - startProcess("./LibreHardwareMonitor/LibreHardwareMonitor.exe"); + isAdmin = isRunAsAdmin(); + if (isAdmin) { + startProcess("./LibreHardwareMonitor/LibreHardwareMonitor.exe"); + } } ~hardwareInfoThread() { + runFlag = false; quit(); wait(); } @@ -284,30 +289,42 @@ public: CloseHandle(hProcess); } protected: + bool runFlag = true; + bool isAdmin = false; + hardwareInfo _hardwareInfo; void run() override { - JsonFetcher* fetcher = new JsonFetcher; - fetcher->moveToThread(this); + if (isAdmin) { + JsonFetcher* fetcher = new JsonFetcher; + fetcher->moveToThread(this); - connect(fetcher, &JsonFetcher::jsonReady, this, [this](const QJsonObject& obj) { - //qDebug() << calculateOverallCpuLoad(obj); - //qDebug() << calculateOverallCpuTemperature(obj); - //qDebug() << parseMemoryUsage(obj); - emit addCpuUsageData(calculateOverallCpuLoad(obj)); - emit addCpuTempData(calculateMaxCpuTemperature(obj)); - emit addMemUsageData(parseMemoryUsage(obj)); - }); - connect(fetcher, &JsonFetcher::error, this, [](const QString& err) { - //qWarning() << "Error:" << err; - }); + connect(fetcher, &JsonFetcher::jsonReady, this, [this](const QJsonObject& obj) { + //qDebug() << calculateOverallCpuLoad(obj); + //qDebug() << calculateOverallCpuTemperature(obj); + //qDebug() << parseMemoryUsage(obj); + emit addCpuUsageData(calculateOverallCpuLoad(obj)); + emit addCpuTempData(calculateMaxCpuTemperature(obj)); + emit addMemUsageData(parseMemoryUsage(obj)); + }); + connect(fetcher, &JsonFetcher::error, this, [](const QString& err) { + //qWarning() << "Error:" << err; + }); - // 定时器驱动 fetch - QTimer timer; - connect(&timer, &QTimer::timeout, fetcher, [fetcher]() { - fetcher->fetch(QUrl("http://127.0.0.1:8085/data.json")); - }); - timer.start(2000); + // 定时器驱动 fetch + QTimer timer; + connect(&timer, &QTimer::timeout, fetcher, [fetcher]() { + fetcher->fetch(QUrl("http://127.0.0.1:8085/data.json")); + }); + timer.start(2000); - exec(); // 启动事件循环 + exec(); // 启动事件循环 + } + else { + while (runFlag) { + emit addCpuUsageData(_hardwareInfo.getAvgCpuUseage()); + emit addMemUsageData(_hardwareInfo.getAvgMemUseage()); + QThread::msleep(2000); + } + } } signals: void addCpuUsageData(double input); diff --git a/src/launcher/logger/logService.cpp b/src/launcher/logger/logService.cpp index 6b25770..86695cc 100644 --- a/src/launcher/logger/logService.cpp +++ b/src/launcher/logger/logService.cpp @@ -1,41 +1,91 @@ -#include +#include "logService.h" +#include +#include -logService* _logService = nullptr; +logService* logService::_instance = nullptr; +std::mutex logService::_instanceMutex; + +logService* logService::getInstance() +{ + std::lock_guard lock(_instanceMutex); + if (_instance == nullptr) { + _instance = new logService(); + } + return _instance; +} logService::logService() - //stdLogger(logBasePath,"stdLog"), - //qtLogger(logBasePath, "Log") { - //spdlog::init_thread_pool(8192,1); - qtLogger = new SpdLogger(logBasePath, "Log"); - _logToQtWidget = new logToQtWidget(); - _logService = this; - //STD日志 - _stdConsoleRedirector = new stdConsoleRedirector(std::cout); - //QT日志 - _qtRediretor = new qtRediretor(); - //STD日志到Qt日志界面 Qt主界面 spdLog - _stdConsoleRedirector->registerCallback([&](const std::string& output) { - QString outPutMsg(QString::fromStdString(output)); - _logToQtWidget->sendStdLogSignal(outPutMsg);//Qt日志界面 - _logToQtWidget->sendMainWindowStdLogSignal(outPutMsg);//Qt主界面 - _logService->qtLogger->LogDebug("[STD]" + output);//spdLog + try { + // 确保日志目录存在 + std::filesystem::create_directories(logBasePath); + + // 初始化日志组件 + qtLogger = std::make_unique(const_cast(logBasePath), "Log"); + _logToQtWidget = std::make_unique(); + + // STD日志重定向器 + _stdConsoleRedirector = std::make_unique(std::cout); + + // QT日志重定向器 + _qtRediretor = std::make_unique(); + + // STD日志到Qt日志界面、Qt主界面、spdLog + _stdConsoleRedirector->registerCallback([this](const std::string& output) { + if (!output.empty() && output != "\n") { + QString outPutMsg = QString::fromStdString(output); + _logToQtWidget->sendStdLogSignal(outPutMsg); // Qt日志界面 + _logToQtWidget->sendMainWindowStdLogSignal(outPutMsg); // Qt主界面 + qtLogger->LogDebug("[STD]" + output); // spdLog + } }); - _stdConsoleRedirector->registerCallback([&](const std::string& output) { - _stdConsoleRedirector->writeToConsole(output); + + // STD日志到控制台 + _stdConsoleRedirector->registerCallback([this](const std::string& output) { + if (!output.empty() && output != "\n") { + _stdConsoleRedirector->writeToConsole(output); + } }); - // QT日志到 spdLog Qt日志界面 - _qtRediretor->registerCallback([&](const QString& output) { - _logService->qtLogger->LogDebug("[QT]" + output.toStdString()); - _logToQtWidget->sendQtLogSignal(output);//Qt日志界面 + + // QT日志到spdLog和Qt日志界面 + _qtRediretor->registerCallback([this](const QString& output) { + if (!output.isEmpty()) { + qtLogger->LogDebug("[QT]" + output.toStdString()); + _logToQtWidget->sendQtLogSignal(output); // Qt日志界面 + } }); - _qtRediretor->registerCallback([&](const QString& output) { - _stdConsoleRedirector->writeToConsole(output.toStdString()); // 逐个字符写入缓冲区 + + // QT日志到控制台 + _qtRediretor->registerCallback([this](const QString& output) { + if (!output.isEmpty()) { + _stdConsoleRedirector->writeToConsole(output.toStdString()); + } }); - + + } catch (const std::exception& e) { + qDebug() << "Failed to initialize logService:" << e.what(); + } } logService::~logService() { - delete _stdConsoleRedirector; - delete _qtRediretor; + try { + // 智能指针会自动释放资源,但我们可以显式重置 + _stdConsoleRedirector.reset(); + _qtRediretor.reset(); + _logToQtWidget.reset(); + qtLogger.reset(); + } catch (const std::exception& e) { + // 析构函数中不应抛出异常,只记录错误 + qDebug() << "Error in logService destructor:" << e.what(); + } +} + +void logService::disableConsole() +{ + if (_stdConsoleRedirector) { + _stdConsoleRedirector->eraseSecondCallback(); + } + if (_qtRediretor) { + _qtRediretor->eraseSecondCallback(); + } } \ No newline at end of file diff --git a/src/launcher/logger/logService.h b/src/launcher/logger/logService.h index 0387a50..e3adc0e 100644 --- a/src/launcher/logger/logService.h +++ b/src/launcher/logger/logService.h @@ -1,14 +1,20 @@ +#pragma once + #include +#include +#include #include #include #include #include +#include #include -#include -#include -#include -#include -static std::string logBasePath = "./Log/"; + +#include "spdLogSupport.hpp" +#include "stdLogRediretor.hpp" +#include "qtLogRediretor.h" + +static const std::string logBasePath = "./Log/"; class logToQtWidget : public QObject { Q_OBJECT @@ -26,25 +32,36 @@ public: emit mainWindowStdLogSignal(str); } signals: - void mainWindowStdLogSignal(QString logMsg); - void stdLogSignal(QString logMsg); - void qtLogSignal(QString logMsg); + void mainWindowStdLogSignal(const QString& logMsg); + void stdLogSignal(const QString& logMsg); + void qtLogSignal(const QString& logMsg); }; class logService : public QThread { + Q_OBJECT public: - qtRediretor* _qtRediretor; - stdConsoleRedirector* _stdConsoleRedirector; - logToQtWidget* _logToQtWidget; - //SpdLogger stdLogger; - SpdLogger* qtLogger; - void disableConsole() { - _stdConsoleRedirector->eraseSecondCallback(); - _qtRediretor->eraseSecondCallback(); - } logService(); ~logService(); -}; - -#pragma once \ No newline at end of file + // 获取单例实例 + static logService* getInstance(); + + // 禁用控制台输出 + void disableConsole(); + + // 获取日志组件 + logToQtWidget* getLogWidget() const { return _logToQtWidget.get(); } + +private: + std::unique_ptr _qtRediretor; + std::unique_ptr _stdConsoleRedirector; + std::unique_ptr _logToQtWidget; + std::unique_ptr qtLogger; + + static logService* _instance; + static std::mutex _instanceMutex; + + // 禁用拷贝构造和赋值操作 + logService(const logService&) = delete; + logService& operator=(const logService&) = delete; +}; \ No newline at end of file diff --git a/src/launcher/logger/qtLogRediretor.cpp b/src/launcher/logger/qtLogRediretor.cpp index fdf6ce5..f3ca370 100644 --- a/src/launcher/logger/qtLogRediretor.cpp +++ b/src/launcher/logger/qtLogRediretor.cpp @@ -1,66 +1,52 @@ -#include +#include "qtLogRediretor.h" +#include +#include -class qtRediretor; -qtRediretor* qtRediretor_Ptr = nullptr; -static void qtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) { - // 获取当前时间 - //QString timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); - // 构建日志输出字符串 +// 全局指针,用于消息处理函数 +static qtRediretor* qtRediretor_Ptr = nullptr; - //SAMPLE - //[2025-06-05 11:08:55] [Thread 6808] [debug] [QT][Hd_SocketModule_FinsTcp.cpp:307][bool __cdecl Hd_SocketModule_FinsTcp::writeData(class std::vector > &,class QByteArray &,class nlohmann::json_abi_v3_11_3::basic_json,class std::allocator >,bool,__int64,unsigned __int64,double,class std::allocator,struct nlohmann::json_abi_v3_11_3::adl_serializer,class std::vector >,void> &)] [TCP] "write_short_D855_1" - //QString outputMessage = QString("[%1:%2][%3] %4") - // .arg(QFileInfo(context.file).fileName()) - // .arg(context.line) - // .arg(context.function) - // .arg(msg); - //qtRediretor_Ptr->sendMsg(outputMessage); - - //SAMPLE - //[2025-06-05 11:20:50] [Thread 29180] [debug] [QT][Hd_SocketModule_FinsTcp.cpp:307] [TCP] "write_short_D855_1" - QString outputMessage = QString("[%1:%2] %3") - .arg(QFileInfo(context.file).fileName()) - .arg(context.line) - .arg(msg); - qtRediretor_Ptr->sendMsg(outputMessage); - - - - - - //if (_logService != nullptr) - // _logService->qtLogger.LogDebug(outputMessage.toStdString()); - //// 根据消息类型进行不同处理 - //switch (type) { - //case QtDebugMsg: - // //// 打印到控制台 - // //QTextStream(stdout) << outputMessage << endl; - - // //// 也可以将日志写入文件 - // //{ - // // QFile file("debug_log.txt"); - // // if (file.open(QIODevice::Append | QIODevice::Text)) { - // // QTextStream out(&file); - // // out << outputMessage << endl; - // // } - // //} - // break; - //case QtInfoMsg: - // // 可以扩展对信息类型的处理 - // break; - //case QtWarningMsg: - // // 可以扩展对警告类型的处理 - // break; - //case QtCriticalMsg: - // // 可以扩展对严重错误类型的处理 - // break; - //case QtFatalMsg: - // // fatal消息会导致程序崩溃 - // break; - //} +static void qtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + if (!qtRediretor_Ptr) { + return; + } + + // 构建格式化的日志消息 + // 格式: [文件名:行号] 消息内容 + QString outputMessage = QString("[%1:%2] %3") + .arg(QFileInfo(context.file).fileName()) + .arg(context.line) + .arg(msg); + + qtRediretor_Ptr->sendMsg(outputMessage); } + qtRediretor::qtRediretor() { - qtRediretor_Ptr = this; - qInstallMessageHandler(qtMessageHandler); + qtRediretor_Ptr = this; + qInstallMessageHandler(qtMessageHandler); +} + +void qtRediretor::registerCallback(CallbackType callback) +{ + std::lock_guard lock(consoleLock); + callbacks.push_back(callback); +} + +void qtRediretor::sendMsg(const QString& msg) +{ + std::lock_guard lock(consoleLock); + for (const auto& callback : callbacks) { + if (callback) { + callback(msg); + } + } +} + +void qtRediretor::eraseSecondCallback() +{ + std::lock_guard lock(consoleLock); + if (callbacks.size() > 1) { + callbacks.erase(callbacks.begin() + 1, callbacks.end()); + } } \ No newline at end of file diff --git a/src/launcher/logger/qtLogRediretor.h b/src/launcher/logger/qtLogRediretor.h index affabba..ddb9a25 100644 --- a/src/launcher/logger/qtLogRediretor.h +++ b/src/launcher/logger/qtLogRediretor.h @@ -1,27 +1,29 @@ -#include -#include +#pragma once + +#include +#include +#include +#include +#include #include + class qtRediretor { public: qtRediretor(); + ~qtRediretor() = default; + using CallbackType = std::function; - void registerCallback(CallbackType callback) { - callbacks.push_back(callback); - } - void sendMsg(QString& msg) - { - std::lock_guard lock(consoleLock); - for (auto& callback : callbacks) - callback(msg); - } - void eraseSecondCallback() { - std::lock_guard lock(consoleLock); - callbacks.erase(callbacks.begin() + 1, callbacks.end()); - } + + void registerCallback(CallbackType callback); + void sendMsg(const QString& msg); + void eraseSecondCallback(); + + // 禁用拷贝构造和赋值操作 + qtRediretor(const qtRediretor&) = delete; + qtRediretor& operator=(const qtRediretor&) = delete; + private: std::mutex consoleLock; - std::vector callbacks; -}; - -#pragma once \ No newline at end of file + std::vector callbacks; +}; \ No newline at end of file diff --git a/src/launcher/logger/spdLogSupport.hpp b/src/launcher/logger/spdLogSupport.hpp index a59e139..0a9aab0 100644 --- a/src/launcher/logger/spdLogSupport.hpp +++ b/src/launcher/logger/spdLogSupport.hpp @@ -1,40 +1,86 @@ -#include +#pragma once + +#include #include #include +#include #include #include #include #include + #define LOG_DEBUG(logger, msg) \ - (logger).LogDebug((msg), __FILE__, __LINE__); + (logger).LogDebug((msg), __FILE__, __LINE__); class SpdLogger { public: - SpdLogger(std::string& file_path, std::string file_name) { + explicit SpdLogger(std::string& file_path, const std::string& file_name) { try { - spdlog::init_thread_pool(8192, 5); // 初始化线程池 + // 初始化线程池 - 只初始化一次 + static bool thread_pool_initialized = false; + if (!thread_pool_initialized) { + spdlog::init_thread_pool(8192, 2); + thread_pool_initialized = true; + } + + // 创建异步日志器,按天保存 logger_ = spdlog::daily_logger_mt( - file_name, file_path + "/" + file_name + ".log", 0, 0); // 日志按天保存 - logger_->set_level(spdlog::level::debug); // 设置日志级别为 Debug - spdlog::flush_every(std::chrono::seconds(1));//每秒写入一次 - logger_->set_pattern("[%Y-%m-%d %H:%M:%S %e] [Thread %t] [%l] %v"); + file_name, file_path + "/" + file_name + ".log", 0, 0); + + if (logger_) { + logger_->set_level(spdlog::level::debug); + logger_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [Thread %t] [%l] %v"); + + // 设置刷新策略 + spdlog::flush_every(std::chrono::seconds(3)); + logger_->flush_on(spdlog::level::debug); + } } catch (const std::exception& ex) { - std::cout << "Log initialization failed: " << ex.what() << std::endl; + std::cerr << "Log initialization failed: " << ex.what() << std::endl; } } + + ~SpdLogger() { + try { + if (logger_) { + logger_->flush(); + spdlog::drop(logger_->name()); + } + } + catch (const std::exception& ex) { + std::cerr << "Error in SpdLogger destructor: " << ex.what() << std::endl; + } + } + void LogDebug(const std::string& msg) { - if (logger_) { + if (logger_ && !msg.empty()) { logger_->debug(msg); } } - ~SpdLogger() - { - spdlog::shutdown(); + + void LogInfo(const std::string& msg) { + if (logger_ && !msg.empty()) { + logger_->info(msg); + } } + + void LogWarning(const std::string& msg) { + if (logger_ && !msg.empty()) { + logger_->warn(msg); + } + } + + void LogError(const std::string& msg) { + if (logger_ && !msg.empty()) { + logger_->error(msg); + } + } + + // 禁用拷贝构造和赋值操作 + SpdLogger(const SpdLogger&) = delete; + SpdLogger& operator=(const SpdLogger&) = delete; + private: - std::shared_ptr logger_; // 日志器实例 -}; - - -#pragma once \ No newline at end of file + std::shared_ptr logger_; +}; \ No newline at end of file diff --git a/src/launcher/logger/stdLogRediretor.hpp b/src/launcher/logger/stdLogRediretor.hpp index c8ef888..3f7b933 100644 --- a/src/launcher/logger/stdLogRediretor.hpp +++ b/src/launcher/logger/stdLogRediretor.hpp @@ -1,4 +1,5 @@ #pragma once + #include #include #include @@ -9,6 +10,10 @@ #include #include #include +#include +#include +#include +#include #ifdef _WIN32 #include @@ -19,44 +24,93 @@ public: using CallbackType = std::function; explicit stdConsoleRedirector(std::ostream& stream) - : originalStream(stream), originalBuffer(stream.rdbuf(this)) { + : originalStream(stream), originalBuffer(stream.rdbuf(this)), + stopAsyncThread(false), asyncProcessingEnabled(true) { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif + // 启动异步处理线程 + asyncThread = std::thread(&stdConsoleRedirector::asyncProcessorThread, this); } ~stdConsoleRedirector() { - flushBuffer(); // 确保最后一行输出 - originalStream.rdbuf(originalBuffer); // 恢复 std::cout + try { + // 停止异步线程 + { + std::lock_guard lock(asyncMutex); + stopAsyncThread = true; + } + asyncCondition.notify_all(); + + if (asyncThread.joinable()) { + asyncThread.join(); + } + + // 处理剩余的buffer + std::lock_guard lock(consoleLock); + flushBufferUnsafe(); // 确保最后一行输出 + originalStream.rdbuf(originalBuffer); // 恢复原始流缓冲区 + } + catch (...) { + // 析构函数中不应抛出异常 + } } void registerCallback(CallbackType callback) { - callbacks.push_back(callback); + if (callback) { + std::lock_guard lock(consoleLock); + callbacks.push_back(callback); + } } + void eraseSecondCallback() { - std::lock_guard lock(consoleLock); - callbacks.erase(callbacks.begin() + 1, callbacks.end()); + std::lock_guard lock(consoleLock); + if (callbacks.size() > 1) { + callbacks.erase(callbacks.begin() + 1, callbacks.end()); + } } + void writeToConsole(const std::string& str) { - std::lock_guard lock(consoleLock); - originalBuffer->sputn(str.c_str(), str.size()); - originalBuffer->sputc('\n'); + if (!str.empty() && originalBuffer) { + std::lock_guard lock(consoleLock); + originalBuffer->sputn(str.c_str(), str.size()); + if (str.back() != '\n') { + originalBuffer->sputc('\n'); + } + } } + + // 设置是否启用异步处理 + void setAsyncProcessing(bool enabled) { + asyncProcessingEnabled = enabled; + } + + // 强制同步处理所有待处理的消息 + void flushAsync() { + std::unique_lock lock(asyncMutex); + asyncCondition.wait(lock, [this] { return asyncQueue.empty(); }); + } + + // 禁用拷贝构造和赋值操作 + stdConsoleRedirector(const stdConsoleRedirector&) = delete; + stdConsoleRedirector& operator=(const stdConsoleRedirector&) = delete; + protected: int overflow(int c) override { if (traits_type::eq_int_type(c, traits_type::eof())) { - flushBuffer(); + std::lock_guard lock(consoleLock); + flushBufferUnsafe(); return traits_type::not_eof(c); } char ch = traits_type::to_char_type(c); { - std::lock_guard lock(consoleLock); + std::lock_guard lock(consoleLock); buffer += ch; if (ch == '\n') { - flushBuffer(); + flushBufferUnsafe(); } } @@ -68,14 +122,87 @@ private: std::streambuf* originalBuffer; std::string buffer; std::vector callbacks; - std::mutex consoleLock; + mutable std::recursive_mutex consoleLock; // 使用递归锁 + + // 异步处理相关 + std::thread asyncThread; + std::queue>> asyncQueue; + std::mutex asyncMutex; + std::condition_variable asyncCondition; + std::atomic stopAsyncThread; + std::atomic asyncProcessingEnabled; void flushBuffer() { + std::lock_guard lock(consoleLock); + flushBufferUnsafe(); + } + + // 异步处理线程 + void asyncProcessorThread() { + while (true) { + std::unique_lock lock(asyncMutex); + asyncCondition.wait(lock, [this] { + return !asyncQueue.empty() || stopAsyncThread; + }); + + if (stopAsyncThread && asyncQueue.empty()) { + break; + } + + // 处理队列中的所有消息 + while (!asyncQueue.empty()) { + auto item = asyncQueue.front(); + asyncQueue.pop(); + lock.unlock(); // 释放锁,避免阻塞新消息入队 + + // 执行回调函数 + const std::string& bufferContent = item.first; + const std::vector& callbackList = item.second; + + for (const auto& callback : callbackList) { + if (callback) { + try { + callback(bufferContent); + } catch (...) { + // 忽略回调函数中的异常,防止影响其他回调 + } + } + } + + lock.lock(); // 重新获取锁继续处理 + } + + // 通知等待线程队列已空 + asyncCondition.notify_all(); + } + } + + // 不安全版本,假设调用者已经持有锁 + void flushBufferUnsafe() { if (!buffer.empty()) { - for (const auto& callback : callbacks) { - callback(buffer); + std::string bufferCopy = buffer; // 复制buffer内容 + buffer.clear(); // 立即清空buffer,这部分必须同步 + + if (asyncProcessingEnabled && !callbacks.empty()) { + // 异步处理回调函数 + std::vector callbacksCopy = callbacks; + { + std::lock_guard lock(asyncMutex); + asyncQueue.emplace(std::move(bufferCopy), std::move(callbacksCopy)); + } + asyncCondition.notify_one(); + } else { + // 同步处理(用于关闭时或禁用异步时) + for (const auto& callback : callbacks) { + if (callback) { + try { + callback(bufferCopy); + } catch (...) { + // 忽略回调函数中的异常 + } + } + } } - buffer.clear(); } } }; diff --git a/src/launcher/main.cpp b/src/launcher/main.cpp index d21ff9e..05d2755 100644 --- a/src/launcher/main.cpp +++ b/src/launcher/main.cpp @@ -36,54 +36,6 @@ bool appIsRuning() sema.release(); return true; } -bool isRunAsAdmin() -{ - BOOL fIsRunAsAdmin = FALSE; - PSID pAdministratorsGroup = NULL; - - // Allocate and initialize a SID of the administrators group. - SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; - if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) - { - return false; - } - - // Determine whether the SID of administrators group is enabled in the primary access token of the process. - if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) - { - fIsRunAsAdmin = FALSE; - } - - // Free the allocated SID. - if (pAdministratorsGroup) - { - FreeSid(pAdministratorsGroup); - } - - return fIsRunAsAdmin; -} -void restartAsAdmin() -{ - TCHAR szPath[MAX_PATH]; - if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) - { - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.lpVerb = TEXT("runas"); - sei.lpFile = szPath; - sei.hwnd = NULL; - sei.nShow = SW_NORMAL; - - if (!ShellExecuteEx(&sei)) - { - DWORD dwError = GetLastError(); - if (dwError == ERROR_CANCELLED) - { - //std::cout << "The user refused to allow privileges elevation.\n"; - } - } - } -} #pragma endregion static bool dumpCallback(const wchar_t* dump_path, const wchar_t* minidump_id, @@ -106,11 +58,11 @@ bool checkResourceExists(const QString& resourcePath) { } void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge* bridge) { - QObject::connect(_core->_logService._logToQtWidget, &logToQtWidget::stdLogSignal, + QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::stdLogSignal, _MainWindow->_logWidget, &logWidget::recvStdLogMsg); - QObject::connect(_core->_logService._logToQtWidget, &logToQtWidget::qtLogSignal, + QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::qtLogSignal, _MainWindow->_logWidget, &logWidget::recvQtLogMsg); - QObject::connect(_core->_logService._logToQtWidget, &logToQtWidget::mainWindowStdLogSignal, + QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::mainWindowStdLogSignal, _MainWindow->_displayWidget, &displayWidget::recvMainWindowStdLogMsg); //BackEnd To Front @@ -129,13 +81,13 @@ void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge* _MainWindow, [=](std::vectordefects) {_MainWindow->_displayWidget->_dayNightShiftHistogramWidget->addDefect(defects); }); QObject::connect(bridge, &qtFuncBridge::setPlcConnectionError, - _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setPlcDisconnected(); }); + _MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setPlcDisconnected(); }); QObject::connect(bridge, &qtFuncBridge::setPlcConnectionOk, - _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setPlcConnected(); }); + _MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setPlcConnected(); }); QObject::connect(bridge, &qtFuncBridge::setCamConnectionError, - _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setCamDisconnected(); }); + _MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setCamDisconnected(); }); QObject::connect(bridge, &qtFuncBridge::setCamConnectionOk, - _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setCamConnected(); }); + _MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setCamConnected(); }); //登录界面 QObject::connect(bridge, &qtFuncBridge::initResult, _MainWindow, &MainWindow::recvInitFinished); @@ -152,7 +104,7 @@ void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge* //排障 QObject::connect(bridge, &qtFuncBridge::runCommand_addBtn, _MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::addBtn); - QObject::connect(_MainWindow->_displayWidget->_runCommandWidget, + QObject::connect(_MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::excuteCommandPreset, [=](QString uuid) {_core->backend.backend->excuteCliCommandPreset(uuid); }); } @@ -184,6 +136,7 @@ int main(int argc, char* argv[]) #pragma endregion appCore _core; + _core.initConfig(); _core._appConfig.consoleHandle = hWnd; qtFuncBridge bridge; // 创建 C++ 对象 //检测是否已运行 @@ -214,7 +167,7 @@ int main(int argc, char* argv[]) #if HIDE_CONSOLE if (_core._appConfig.consoleHandle) { ShowWindow(_core._appConfig.consoleHandle, SW_HIDE); - _core._logService.disableConsole(); + _core._logService->disableConsole(); }// 隐藏控制台窗口 #endif return a.exec(); diff --git a/src/launcher/translation.h b/src/launcher/translation.h new file mode 100644 index 0000000..13540b0 --- /dev/null +++ b/src/launcher/translation.h @@ -0,0 +1,232 @@ +#ifndef TRANSLATION_H +#define TRANSLATION_H + +#include +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +/** + * 单头文件翻译类 + * 支持可扩展的语言section + */ +class Translation { +private: + std::vector sections; // 可扩展的语言列表 + std::map> translations; // [key][language] = text + std::string currentLanguage; + +public: + Translation() : currentLanguage("CN") {} + + // 从JSON文件加载配置 + bool loadFromFile(const std::string& filePath) { + try { + std::ifstream file(filePath); + if (!file.is_open()) { + return false; + } + + json j; + file >> j; + file.close(); + + return parseJson(j); + } catch (const std::exception& e) { + std::cerr << "Error loading translation file: " << e.what() << std::endl; + return false; + } + } + + // 从JSON字符串加载配置 + bool loadFromString(const std::string& jsonString) { + try { + json j = json::parse(jsonString); + return parseJson(j); + } catch (const std::exception& e) { + std::cerr << "Error parsing JSON string: " << e.what() << std::endl; + return false; + } + } + + // 从JSON对象加载配置 + bool loadFromJson(const json& j) { + return parseJson(j); + } + void setLanguage(const std::string& lang) { + for (const auto& section : sections) { + if (section == lang) { + currentLanguage = lang; + return; + } + } + // 如果语言不在sections中,也允许设置(可能是新添加的语言) + currentLanguage = lang; + } + + // 获取当前语言 + std::string getCurrentLanguage() const { + return currentLanguage; + } + + // 获取翻译文本 + std::string translate(const std::string& key) const { + auto it = translations.find(key); + if (it != translations.end()) { + auto langIt = it->second.find(currentLanguage); + if (langIt != it->second.end()) { + return langIt->second; + } + } + return key; // 如果找不到翻译,返回原始key + } + + // 获取指定语言的翻译 + std::string translate(const std::string& key, const std::string& lang) const { + auto it = translations.find(key); + if (it != translations.end()) { + auto langIt = it->second.find(lang); + if (langIt != it->second.end()) { + return langIt->second; + } + } + return key; + } + + // 添加翻译项 + void addTranslation(const std::string& key, const std::string& lang, const std::string& text) { + translations[key][lang] = text; + } + + // 添加语言section + void addSection(const std::string& lang) { + for (const auto& section : sections) { + if (section == lang) return; // 已存在 + } + sections.push_back(lang); + } + + // 获取所有支持的语言 + const std::vector& getSections() const { + return sections; + } + + // 检查是否有指定key的翻译 + bool hasTranslation(const std::string& key) const { + return translations.find(key) != translations.end(); + } + + // 获取所有翻译key + std::vector getAllKeys() const { + std::vector keys; + for (const auto& pair : translations) { + keys.push_back(pair.first); + } + return keys; + } + + // 清空所有数据 + void clear() { + sections.clear(); + translations.clear(); + currentLanguage = "CN"; + } + + // 保存到JSON文件 + bool saveToFile(const std::string& filePath) const { + try { + json j; + j["current_language"] = currentLanguage; + j["section"] = sections; + + json translateObj; + for (const auto& [key, langMap] : translations) { + json keyObj; + for (const auto& [lang, text] : langMap) { + keyObj[lang] = text; + } + translateObj[key] = keyObj; + } + j["translate"] = translateObj; + + std::ofstream file(filePath); + file << j.dump(4); // 格式化输出,缩进4个空格 + file.close(); + return true; + } catch (const std::exception& e) { + std::cerr << "Error saving translation file: " << e.what() << std::endl; + return false; + } + } + + // 转换为JSON字符串 + std::string toJsonString() const { + try { + json j; + j["current_language"] = currentLanguage; + j["section"] = sections; + + json translateObj; + for (const auto& [key, langMap] : translations) { + json keyObj; + for (const auto& [lang, text] : langMap) { + keyObj[lang] = text; + } + translateObj[key] = keyObj; + } + j["translate"] = translateObj; + + return j.dump(4); + } catch (const std::exception& e) { + std::cerr << "Error converting to JSON string: " << e.what() << std::endl; + return "{}"; + } + } + +private: + // 使用nlohmann/json解析 + bool parseJson(const json& j) { + try { + // 解析current_language + if (j.contains("current_language") && j["current_language"].is_string()) { + currentLanguage = j["current_language"].get(); + } + + // 解析sections + if (j.contains("section") && j["section"].is_array()) { + sections.clear(); + for (const auto& section : j["section"]) { + if (section.is_string()) { + addSection(section.get()); + } + } + } + + // 解析translations + if (j.contains("translate") && j["translate"].is_object()) { + for (const auto& [key, langObj] : j["translate"].items()) { + if (langObj.is_object()) { + for (const auto& [lang, text] : langObj.items()) { + if (text.is_string()) { + addTranslation(key, lang, text.get()); + } + } + } + } + } + + return true; + } catch (const std::exception& e) { + std::cerr << "Error parsing JSON: " << e.what() << std::endl; + return false; + } + } +}; + + + +#endif // TRANSLATION_H \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam1213/581-BaoMo.h b/src/mission/581-BaoMo-Cam1213/581-BaoMo.h index 75b95f8..dc48f45 100644 --- a/src/mission/581-BaoMo-Cam1213/581-BaoMo.h +++ b/src/mission/581-BaoMo-Cam1213/581-BaoMo.h @@ -12,7 +12,7 @@ using namespace HDevEngineCpp; class _581_BaoMo : public mission { public: - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger _station_1; generalTrigger _station_2; detParams _params; @@ -22,12 +22,12 @@ public: } bool initCustom() { #pragma region 注册触发器回调 - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_1.init("Camera1","包膜后底托位置度检测相机12",20200,2,1, _params,_serviceManager,bridge, generalAlgoTest, resultCallback_general); - _station_2.init("Camera2", "包膜后底托位置度检测相机13",20400,2,1,_params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + //generalTrigger::resultHandleCallback resultCallback_general = + // ([=](yh_581_address address, _581_Result resultData, std::shared_ptr data) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // }); + _station_1.init("Camera1","包膜后底托位置度检测相机12",20200,2,1, _params,_serviceManager,bridge, generalAlgoTest); + _station_2.init("Camera2", "包膜后底托位置度检测相机13",20400,2,1,_params, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } diff --git a/src/mission/581-BaoMo-Cam1234/581-BaoMo.cpp b/src/mission/581-BaoMo-Cam1234/581-BaoMo.cpp index 0ee499e..a765ef4 100644 --- a/src/mission/581-BaoMo-Cam1234/581-BaoMo.cpp +++ b/src/mission/581-BaoMo-Cam1234/581-BaoMo.cpp @@ -1,5 +1,4 @@ #include <581-BaoMo.h> - mission* createMission() { return new _581_BaoMo(); } diff --git a/src/mission/581-BaoMo-Cam1234/581-BaoMo.h b/src/mission/581-BaoMo-Cam1234/581-BaoMo.h index 81436e5..98d1648 100644 --- a/src/mission/581-BaoMo-Cam1234/581-BaoMo.h +++ b/src/mission/581-BaoMo-Cam1234/581-BaoMo.h @@ -11,127 +11,6 @@ public: handleAiModelCls* cls; handleAiModelCls* cls2; }; -#pragma region 算法 -#include -#include -#include -using namespace HDevEngineCpp; - -_581_BaoMoResult SUB_BaoMoHouDaMian(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, - baoMoHouDaMianDetParams* _detParams) { - _581_BaoMoResult aireuslt; - TextRendererZH textPainter(Paint.cols, Paint.rows, 150); - bool huaShangNg = false; - cv::Mat segImg = ~_detParams->seg->segPtr->Evaluate(src); - std::vector> contours; - cv::findContours(segImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); - bool isOK = true; - for (int i = 0; i < contours.size(); i++) { - cv::Rect rect = cv::boundingRect(contours[i]); - if (rect.width < 100 && rect.height < 100) continue; // 过滤掉小轮廓 - auto clsImgs = cutImg2ClsVec(rect, src, cv::Size(256, 256)); - bool clsIsNg = false; - for (auto& clsImg : clsImgs) { - if (_detParams->cls->Evaluate(clsImg) == 1) { // 假设1表示NG - int clsResult = _detParams->cls2->Evaluate(clsImg); - if (clsResult == 1) { - clsIsNg = true; - huaShangNg = true; - //data->clsOriginImgs.push_back({ std::to_string(i),clsImg }); - } - } - } - cv::Scalar color = cv::Scalar(0, 255, 0); - if (clsIsNg == true) { - color = cv::Scalar(0, 0, 255); - isOK = false; - cv::drawContours(Paint, contours, i, color, 2); - textPainter.putText(Paint, "划伤", cv::Point(rect.x + 10, rect.y - 20), cv::Scalar(0, 255, 0)); - } - //else { - // cv::Mat imgTmp; - // QMutexLocker locker(paintMutex); - // imgTmp.copyTo(Paint(rect)); - // cv::rectangle(Paint, rect, color, 3); - //} - - //putTextZH(Paint, "NG", cv::Point(rect.x + 10, rect.y - 20), 25, color); - } - if (huaShangNg == true) - aireuslt.defects.push_back("划伤"); - return aireuslt; -} -static _581_BaoMoResult ALGO_BaoMoHouDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams) -{ - _581_BaoMoResult _result; - qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; - - ///////////////////取图//处理////////////////// - if (data->oriImgs.size() != 1) - { - qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); - return _581_BaoMoResult(); - } - if (data->oriImgs[0].rows == 100) { - cv::Mat Paint; - data->oriImgs[0].copyTo(Paint); - cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); - return _581_BaoMoResult(); - } - - cv::Mat Paint; - //QMutex paintMutex; - clock_t start, finish; - start = clock(); - - cv::Mat src1 = data->oriImgs[0]; - cv::Mat srcHalf; - cv::resize(src1, srcHalf, cv::Size(0, 0), 0.5, 0.5); - if (srcHalf.channels() != 3) - cv::cvtColor(srcHalf, Paint, cv::COLOR_GRAY2BGR); - else - srcHalf.copyTo(Paint); - //TextRendererZH textPainter(Paint.cols, Paint.rows, 150); - //std::future <_581_Result> handleAiFuture = std::async(std::launch::async, _BaoMoHouDaMian, data, srcHalf, Paint, _detParams); - /*HalconCpp::HObject in_Image = MatToHObject(src1); - HDevEngineCpp::HDevProcedure proc("_4_Cal_Long_Coatingcover_Dist"); - HDevProcedureCall procedureCall(proc); - procedureCall.SetInputIconicParamObject("in_Image", in_Image); - procedureCall.SetInputCtrlParamTuple("in_xResolution", HTuple(0.0308812)); - procedureCall.SetInputCtrlParamTuple("in_yResolution", HTuple(0.029527)); - procedureCall.Execute(); - HTuple out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance"); - HTuple out_Line = procedureCall.GetOutputCtrlParamTuple("out_Line"); - HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); - int outFlag = out_Flag.D();*/ - //handleAiFuture.wait(); - //_result = handleAiFuture.get(); - //if (outFlag == 1) { - // for (int i = 0; i < out_Line.Length() / 4; i++) { - // cv::line(Paint, cv::Point(out_Line[i * 4 + 1].D() / 2, out_Line[i * 4].D()) / 2, - // cv::Point(out_Line[i * 4 + 3].D() / 2, out_Line[i * 4 + 2].D() / 2), - // cv::Scalar(0, 255, 0), 5); - // } - // /*out_Distance[0]: 上端盖到膜的距离< / c> - // * out_Distance[1] : 中端盖到膜的距离< / c> - // * out_Distance[2] : 下端盖到膜的距离< / c> - // * out_Distance[3] : 电芯宽度 < / c> - // * out_Distance[4] : 电芯高度< / c>*/ - // textPainter.putText(Paint, "上端盖到膜的距离:" + std::to_string(out_Distance[0].D()), cv::Point(50, 150), cv::Scalar(0, 255, 0)); - // textPainter.putText(Paint, "中端盖到膜的距离:" + std::to_string(out_Distance[1].D()), cv::Point(50, 350), cv::Scalar(0, 255, 0)); - // textPainter.putText(Paint, "下端盖到膜的距离:" + std::to_string(out_Distance[2].D()), cv::Point(50, 550), cv::Scalar(0, 255, 0)); - // textPainter.putText(Paint, "电芯宽度:" + std::to_string(out_Distance[3].D()), cv::Point(50, 750), cv::Scalar(0, 255, 0)); - // textPainter.putText(Paint, "电芯高度:" + std::to_string(out_Distance[4].D()), cv::Point(50, 950), cv::Scalar(0, 255, 0)); - //} - //else { - // textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); - //} - - data->resultImgs.push_back(Paint); - - return _result; -} -#pragma endregion //class _581Baomo_BaoMoHouShangDaMian { //public: // baoMoHouDaMianDetParams _detParams; @@ -228,14 +107,134 @@ static _581_BaoMoResult ALGO_BaoMoHouDaMian(std::shared_ptr data, baoM // qtFuncBridge* bridge; // ServiceManager* _serviceManager = nullptr; //}; + +#include +#include +#include +using namespace HDevEngineCpp; + +_581_BaoMoResult SUB_BaoMoHouDaMian(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, + baoMoHouDaMianDetParams* _detParams) { + _581_BaoMoResult aireuslt; + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + bool huaShangNg = false; + cv::Mat segImg = ~_detParams->seg->segPtr->Evaluate(src); + std::vector> contours; + cv::findContours(segImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + bool isOK = true; + for (int i = 0; i < contours.size(); i++) { + cv::Rect rect = cv::boundingRect(contours[i]); + if (rect.width < 100 && rect.height < 100) continue; // 过滤掉小轮廓 + auto clsImgs = cutImg2ClsVec(rect, src, cv::Size(256, 256)); + bool clsIsNg = false; + for (auto& clsImg : clsImgs) { + if (_detParams->cls->Evaluate(clsImg) == 1) { // 假设1表示NG + int clsResult = _detParams->cls2->Evaluate(clsImg); + if (clsResult == 1) { + clsIsNg = true; + huaShangNg = true; + //data->clsOriginImgs.push_back({ std::to_string(i),clsImg }); + } + } + } + cv::Scalar color = cv::Scalar(0, 255, 0); + if (clsIsNg == true) { + color = cv::Scalar(0, 0, 255); + isOK = false; + cv::drawContours(Paint, contours, i, color, 2); + textPainter.putText(Paint, "划伤", cv::Point(rect.x + 10, rect.y - 20), cv::Scalar(0, 255, 0)); + } + //else { + // cv::Mat imgTmp; + // QMutexLocker locker(paintMutex); + // imgTmp.copyTo(Paint(rect)); + // cv::rectangle(Paint, rect, color, 3); + //} + + //putTextZH(Paint, "NG", cv::Point(rect.x + 10, rect.y - 20), 25, color); + } + if (huaShangNg == true) + aireuslt.defects.push_back("划伤"); + return aireuslt; +} +static bool ALGO_BaoMoHouDaMian(std::shared_ptr data, + baoMoHouDaMianDetParams* _detParams, + yh_581_address address) { + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() != 1) { + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[0].copyTo(Paint); + cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); + return false; + } + + cv::Mat Paint; + //QMutex paintMutex; + clock_t start, finish; + start = clock(); + + cv::Mat src1 = data->oriImgs[0]; + cv::Mat srcHalf; + cv::resize(src1, srcHalf, cv::Size(0, 0), 0.5, 0.5); + if (srcHalf.channels() != 3) + cv::cvtColor(srcHalf, Paint, cv::COLOR_GRAY2BGR); + else + srcHalf.copyTo(Paint); + //TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + //std::future <_581_Result> handleAiFuture = std::async(std::launch::async, _BaoMoHouDaMian, data, srcHalf, Paint, _detParams); + /*HalconCpp::HObject in_Image = MatToHObject(src1); + HDevEngineCpp::HDevProcedure proc("_4_Cal_Long_Coatingcover_Dist"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_xResolution", HTuple(0.0308812)); + procedureCall.SetInputCtrlParamTuple("in_yResolution", HTuple(0.029527)); + procedureCall.Execute(); + HTuple out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance"); + HTuple out_Line = procedureCall.GetOutputCtrlParamTuple("out_Line"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + int outFlag = out_Flag.D();*/ + //handleAiFuture.wait(); + //_result = handleAiFuture.get(); + //if (outFlag == 1) { + // for (int i = 0; i < out_Line.Length() / 4; i++) { + // cv::line(Paint, cv::Point(out_Line[i * 4 + 1].D() / 2, out_Line[i * 4].D()) / 2, + // cv::Point(out_Line[i * 4 + 3].D() / 2, out_Line[i * 4 + 2].D() / 2), + // cv::Scalar(0, 255, 0), 5); + // } + // /*out_Distance[0]: 上端盖到膜的距离< / c> + // * out_Distance[1] : 中端盖到膜的距离< / c> + // * out_Distance[2] : 下端盖到膜的距离< / c> + // * out_Distance[3] : 电芯宽度 < / c> + // * out_Distance[4] : 电芯高度< / c>*/ + // textPainter.putText(Paint, "上端盖到膜的距离:" + std::to_string(out_Distance[0].D()), cv::Point(50, 150), cv::Scalar(0, 255, 0)); + // textPainter.putText(Paint, "中端盖到膜的距离:" + std::to_string(out_Distance[1].D()), cv::Point(50, 350), cv::Scalar(0, 255, 0)); + // textPainter.putText(Paint, "下端盖到膜的距离:" + std::to_string(out_Distance[2].D()), cv::Point(50, 550), cv::Scalar(0, 255, 0)); + // textPainter.putText(Paint, "电芯宽度:" + std::to_string(out_Distance[3].D()), cv::Point(50, 750), cv::Scalar(0, 255, 0)); + // textPainter.putText(Paint, "电芯高度:" + std::to_string(out_Distance[4].D()), cv::Point(50, 950), cv::Scalar(0, 255, 0)); + //} + //else { + // textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); + //} + + data->resultImgs.push_back(Paint); + + return false; +} + class _581_BaoMo : public mission { public: - using baoMoHouDaMianTrigger = _581_Dgh_triggerTemplate; + using baoMoHouDaMianTrigger = _581_Union_triggerTemplate; baoMoHouDaMianTrigger _station_1; baoMoHouDaMianTrigger _station_2; baoMoHouDaMianDetParams _baoMoHouDaMianDetParams; - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger _station_3; generalTrigger _station_4; detParams _detParams; @@ -245,19 +244,11 @@ public: } bool initCustom() { #pragma region 注册触发器回调 - baoMoHouDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouDaMian = - ([=](yh_581_address address, _581_BaoMoResult, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_1.init("Camera1","包膜前外观检测大面相机1(上大面)", 18000,2, 1, _baoMoHouDaMianDetParams,_serviceManager, bridge, ALGO_BaoMoHouDaMian, resultCallback_BaoMoHouDaMian); - _station_2.init("Camera2", "包膜前外观检测大面相机2(下大面)", 18200,2, 1, _baoMoHouDaMianDetParams, _serviceManager,bridge, ALGO_BaoMoHouDaMian, resultCallback_BaoMoHouDaMian); + _station_1.init("Camera1","包膜前外观检测大面相机1(上大面)", 18000,2, 1, _baoMoHouDaMianDetParams,_serviceManager, bridge, ALGO_BaoMoHouDaMian); + _station_2.init("Camera2", "包膜前外观检测大面相机2(下大面)", 18200,2, 1, _baoMoHouDaMianDetParams, _serviceManager,bridge, ALGO_BaoMoHouDaMian); - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_3.init("Camera3", "包膜前产品边缘检测大面相机3(下大面2)", 18400,2, 2, _detParams,_serviceManager,bridge, generalAlgoTest, resultCallback_general); - _station_4.init("Camera4", "包膜前前产品边缘检测大面相机4(下大面2)", 18600 ,2, 2, _detParams, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + _station_3.init("Camera3", "包膜前产品边缘检测大面相机3(下大面2)", 18400,2, 2, _detParams,_serviceManager,bridge, generalAlgoTest); + _station_4.init("Camera4", "包膜前前产品边缘检测大面相机4(下大面2)", 18600 ,2, 2, _detParams, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } @@ -270,6 +261,4 @@ public: - - #pragma once \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam5678/581-BaoMo.h b/src/mission/581-BaoMo-Cam5678/581-BaoMo.h index de3a7f0..aac6b37 100644 --- a/src/mission/581-BaoMo-Cam5678/581-BaoMo.h +++ b/src/mission/581-BaoMo-Cam5678/581-BaoMo.h @@ -17,9 +17,9 @@ public: #include #include using namespace HDevEngineCpp; -_581_BaoMoResult BaoMoHou_DaMianAi(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, +std::vector BaoMoHou_DaMianAi(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, baoMoHouDaMianDetParams* _detParams) { - _581_BaoMoResult aireuslt; + std::vector defects; TextRendererZH textPainter(Paint.cols, Paint.rows, 150); bool huaShangNg = false; cv::Mat segImg = ~_detParams->seg->segPtr->Evaluate(src); @@ -57,27 +57,26 @@ _581_BaoMoResult BaoMoHou_DaMianAi(std::shared_ptr data, cv::Mat src, //putTextZH(Paint, "NG", cv::Point(rect.x + 10, rect.y - 20), 25, color); } if (huaShangNg == true) - aireuslt.defects.push_back("划伤"); - return aireuslt; + defects.push_back("划伤"); + return defects; } #pragma endregion -#pragma region 上大面 -static _581_BaoMoResult BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams) +#pragma region 算法 +static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address addresss) { - _581_BaoMoResult _result; qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; ///////////////////取图//处理////////////////// if (data->oriImgs.size() != 1) { qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); - return _581_BaoMoResult(); + return false; } if (data->oriImgs[0].rows == 150) { cv::Mat Paint; data->oriImgs[0].copyTo(Paint); cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); - return _581_BaoMoResult(); + return false; } cv::Mat Paint; @@ -93,7 +92,7 @@ static _581_BaoMoResult BaoMoHou_ShangDaMian(std::shared_ptr data, bao else srcHalf.copyTo(Paint); TextRendererZH textPainter(Paint.cols, Paint.rows, 150); - std::future <_581_BaoMoResult> handleAiFuture = std::async(std::launch::async, BaoMoHou_DaMianAi, data, srcHalf, Paint, _detParams); + std::future > handleAiFuture = std::async(std::launch::async, BaoMoHou_DaMianAi, data, srcHalf, Paint, _detParams); HalconCpp::HObject in_Image = MatToHObject(src1); HDevEngineCpp::HDevProcedure proc("_4_Cal_Long_Coatingcover_Dist"); HDevProcedureCall procedureCall(proc); @@ -106,7 +105,7 @@ static _581_BaoMoResult BaoMoHou_ShangDaMian(std::shared_ptr data, bao HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); int outFlag = out_Flag.D(); handleAiFuture.wait(); - _result = handleAiFuture.get(); + auto defects = handleAiFuture.get(); if (outFlag == 1) { for (int i = 0; i < out_Line.Length() / 4; i++) { cv::line(Paint, cv::Point(out_Line[i * 4 + 1].D(), out_Line[i * 4].D()) / 2, @@ -130,8 +129,8 @@ static _581_BaoMoResult BaoMoHou_ShangDaMian(std::shared_ptr data, bao } data->resultImgs.push_back(Paint); - - return _result; + data->service->_missionResultHandle->handleAllResult(data->SNcode, !defects.size() > 0, defects); + return true; } //class _581Baomo_BaoMoHouShangDaMian { //public: @@ -183,24 +182,21 @@ static _581_BaoMoResult BaoMoHou_ShangDaMian(std::shared_ptr data, bao // qtFuncBridge* bridge; // ServiceManager* _serviceManager = nullptr; //}; -#pragma endregion -#pragma region 下大面 -static _581_BaoMoResult BaoMoHou_XiaDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams) +static bool BaoMoHou_XiaDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address addresss) { - _581_BaoMoResult _result; qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; ///////////////////取图//处理////////////////// if (data->oriImgs.size() != 1) { qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); - return _581_BaoMoResult(); + return false; } if (data->oriImgs[0].rows == 150) { cv::Mat Paint; data->oriImgs[0].copyTo(Paint); cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); - return _581_BaoMoResult(); + return false; } cv::Mat Paint; @@ -215,7 +211,7 @@ static _581_BaoMoResult BaoMoHou_XiaDaMian(std::shared_ptr data, baoMo cv::cvtColor(srcHalf, Paint, cv::COLOR_GRAY2BGR); else srcHalf.copyTo(Paint); - _result = BaoMoHou_DaMianAi(data, srcHalf, Paint, _detParams); + auto _result = BaoMoHou_DaMianAi(data, srcHalf, Paint, _detParams); //TextRendererZH textPainter(Paint.cols, Paint.rows, 150); //std::future <_581_BaoMoResult> handleAiFuture = std::async(std::launch::async, BaoMoHou_XiaMianAi, data, srcHalf, Paint, _detParams); //HalconCpp::HObject in_Image = MatToHObject(src1); @@ -254,7 +250,7 @@ static _581_BaoMoResult BaoMoHou_XiaDaMian(std::shared_ptr data, baoMo data->resultImgs.push_back(Paint); - return _result; + return true; } //class _581Baomo_BaoMoHouXiaDaMian { //public: @@ -310,11 +306,11 @@ static _581_BaoMoResult BaoMoHou_XiaDaMian(std::shared_ptr data, baoMo class _581_BaoMo : public mission { public: - using baoMoHouShangDaMianTrigger = _581_Dgh_triggerTemplate; + using baoMoHouShangDaMianTrigger = _581_Union_triggerTemplate; baoMoHouShangDaMianTrigger _station_1;//shangdamian baoMoHouShangDaMianTrigger _station_3;//shangdamian - using baoMoHouXiaDaMianTrigger = _581_Dgh_triggerTemplate; + using baoMoHouXiaDaMianTrigger = _581_Union_triggerTemplate; baoMoHouXiaDaMianTrigger _station_2;//xiadamian baoMoHouXiaDaMianTrigger _station_4;//xiadamian @@ -327,19 +323,21 @@ public: bool initCustom() { #pragma region 注册触发器回调 - baoMoHouShangDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouShangDaMian = - ([=](yh_581_address address, _581_BaoMoResult, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_1.init("Camera1", "包膜后大面外观检测相机5(上大面1)",18800,2,1, _baoMoHouDaMianDetParams, _serviceManager,bridge, BaoMoHou_ShangDaMian, resultCallback_BaoMoHouShangDaMian); - _station_3.init("Camera3", "包膜后大面外观检测相机7(上大面2)", 19200, 2, 1, _baoMoHouDaMianDetParams, _serviceManager, bridge, BaoMoHou_ShangDaMian, resultCallback_BaoMoHouShangDaMian); + //baoMoHouShangDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouShangDaMian = + // ([=](yh_581_address address, _581_BaoMoResult resultData, std::shared_ptr data ) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // _serviceManager->_missionResultHandle->handleAllResult(data->SNcode, resultData.result, resultData.defects); + // }); + _station_1.init("Camera1", "包膜后大面外观检测相机5(上大面1)",18800,2,1, _baoMoHouDaMianDetParams, _serviceManager,bridge, BaoMoHou_ShangDaMian); + _station_3.init("Camera3", "包膜后大面外观检测相机7(上大面2)", 19200, 2, 1, _baoMoHouDaMianDetParams, _serviceManager, bridge, BaoMoHou_ShangDaMian); - baoMoHouXiaDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouXiaDaMian = - ([=](yh_581_address address, _581_BaoMoResult, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_2.init("Camera2", "包膜后大面外观检测相机6(下大面四角1)", 19000, 2, 1, _baoMoHouDaMianDetParams, _serviceManager, bridge, BaoMoHou_XiaDaMian, resultCallback_BaoMoHouXiaDaMian); - _station_4.init("Camera4", "包膜后大面外观检测相机8(下大面四角2)",19400,2,1, _baoMoHouDaMianDetParams, _serviceManager, bridge, BaoMoHou_XiaDaMian, resultCallback_BaoMoHouXiaDaMian); + //baoMoHouXiaDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouXiaDaMian = + // ([=](yh_581_address address, _581_BaoMoResult resultData, std::shared_ptr data) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // _serviceManager->_missionResultHandle->handleAllResult(data->SNcode, resultData.result, resultData.defects); + // }); + _station_2.init("Camera2", "包膜后大面外观检测相机6(下大面四角1)", 19000, 2, 1, _baoMoHouDaMianDetParams, _serviceManager, bridge, BaoMoHou_XiaDaMian); + _station_4.init("Camera4", "包膜后大面外观检测相机8(下大面四角2)",19400,2,1, _baoMoHouDaMianDetParams, _serviceManager, bridge, BaoMoHou_XiaDaMian); #pragma endregion return true; } diff --git a/src/mission/581-BaoMo-Cam91011/581-BaoMo.cpp b/src/mission/581-BaoMo-Cam91011/581-BaoMo.cpp index 42e9eba..6953511 100644 --- a/src/mission/581-BaoMo-Cam91011/581-BaoMo.cpp +++ b/src/mission/581-BaoMo-Cam91011/581-BaoMo.cpp @@ -7,9 +7,9 @@ void destroyMission(mission* _mission) { delete _mission; } -_581_BaoMoResult _BaoMoHouDaMian(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, +std::vector < std::string> _BaoMoHouDaMian(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, baoMoHouDaMianDetParams* _detParams) { - _581_BaoMoResult aireuslt; + std::vector < std::string> aireuslt; TextRendererZH textPainter(Paint.cols, Paint.rows, 150); bool huaShangNg = false; cv::Mat segImg = ~_detParams->seg->segPtr->Evaluate(src); @@ -48,25 +48,24 @@ _581_BaoMoResult _BaoMoHouDaMian(std::shared_ptr data, cv::Mat src, cv //putTextZH(Paint, "NG", cv::Point(rect.x + 10, rect.y - 20), 25, color); } if (huaShangNg == true) - aireuslt.defects.push_back("划伤"); + aireuslt.push_back("划伤"); return aireuslt; } -_581_BaoMoResult ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams){ - _581_BaoMoResult _result; +bool ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams,yh_581_address address){ qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; - + std::vector < std::string> defects; ///////////////////取图//处理////////////////// if (data->oriImgs.size() != 1) { qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); - return _581_BaoMoResult(); + return false; } if (data->oriImgs[0].rows == 100) { cv::Mat Paint; data->oriImgs[0].copyTo(Paint); cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); - return _581_BaoMoResult(); + return false; } cv::Mat Paint; @@ -111,10 +110,11 @@ _581_BaoMoResult ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaM } else { textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); - _result.defects.push_back("算法不良"); + defects.push_back("算法不良"); } - + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + data->service->_missionResultHandle->handleAllResult(data->SNcode, !defects.size()>0, defects); data->resultImgs.push_back(Paint); - return _result; + return true; } \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam91011/581-BaoMo.h b/src/mission/581-BaoMo-Cam91011/581-BaoMo.h index 658582b..e6b5572 100644 --- a/src/mission/581-BaoMo-Cam91011/581-BaoMo.h +++ b/src/mission/581-BaoMo-Cam91011/581-BaoMo.h @@ -1,9 +1,5 @@ #include #include -struct _581_BaoMoResult{ - bool result = false; - std::vector < std::string> defects; -}; class baoMoHouDaMianDetParams { public: handleAiModelSeg* seg; @@ -17,16 +13,16 @@ public: using namespace HDevEngineCpp; -static _581_BaoMoResult ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams); +static bool ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams,yh_581_address address); #pragma endregion class _581_BaoMo : public mission { public: - using baoMoHouDaMianTrigger = _581_Dgh_triggerTemplate; + using baoMoHouDaMianTrigger = _581_Union_triggerTemplate; baoMoHouDaMianTrigger _station_1; baoMoHouDaMianTrigger _station_2; - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger _station_3; baoMoHouDaMianDetParams _baoMoHouDaMianDetParams; @@ -42,18 +38,18 @@ public: bool initCustom() { #pragma region 注册触发器回调 - baoMoHouDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouCeMian = - ([=](yh_581_address address, _581_BaoMoResult, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_1.init("Camera1","包膜后侧面贴胶错位检测相机9",19600,2,1,_baoMoHouDaMianDetParams,_serviceManager, bridge, ALGO_BaoMoHouCeMian, resultCallback_BaoMoHouCeMian); - _station_2.init("Camera2", "包膜后侧面贴胶错位检测相机10",19800,2,1, _baoMoHouDaMianDetParams, _serviceManager, bridge, ALGO_BaoMoHouCeMian, resultCallback_BaoMoHouCeMian); + //baoMoHouDaMianTrigger::resultHandleCallback resultCallback_BaoMoHouCeMian = + // ([=](yh_581_address address, _581_BaoMoResult, std::shared_ptr ) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // }); + _station_1.init("Camera1","包膜后侧面贴胶错位检测相机9",19600,2,1,_baoMoHouDaMianDetParams,_serviceManager, bridge, ALGO_BaoMoHouCeMian); + _station_2.init("Camera2", "包膜后侧面贴胶错位检测相机10",19800,2,1, _baoMoHouDaMianDetParams, _serviceManager, bridge, ALGO_BaoMoHouCeMian); - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - _station_3.init("Camera3", "包膜后外观检测大面相机11(下大面)",20000,2,1, _detParams, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + //generalTrigger::resultHandleCallback resultCallback_general = + // ([=](yh_581_address address, _581_Result, std::shared_ptr ) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // }); + _station_3.init("Camera3", "包膜后外观检测大面相机11(下大面)",20000,2,1, _detParams, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } diff --git a/src/mission/581-Dgh-CB-1/581-Dgh-CB-1.h b/src/mission/581-Dgh-CB-1/581-Dgh-CB-1.h index 82c59a4..981892d 100644 --- a/src/mission/581-Dgh-CB-1/581-Dgh-CB-1.h +++ b/src/mission/581-Dgh-CB-1/581-Dgh-CB-1.h @@ -19,7 +19,7 @@ using namespace HDevEngineCpp; class _581_Dgh : public mission { public: - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger dgh_cb_yh_3d_1; generalTrigger dgh_cb_yh_3d_2; generalTrigger dgh_cb_yh_3d_3; @@ -29,7 +29,6 @@ public: generalTrigger dgh_cb_mh_3d_2; generalTrigger dgh_cb_mh_3d_3; generalTrigger dgh_cb_mh_3d_4; - summaryData<_581_Result> _summaryData; detParams _params; void onConfigReloaded() { @@ -38,19 +37,19 @@ public: } bool initCustom() { #pragma region 注册触发器回调 - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - dgh_cb_yh_3d_1.init("Camera1", "长边预焊前3D-1", 18000,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_yh_3d_2.init("Camera2", "长边预焊前3D-2", 18200,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_yh_3d_3.init("Camera3", "长边预焊前3D-3", 18400,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_yh_3d_4.init("Camera4", "长边预焊前3D-4", 18600,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + //generalTrigger::resultHandleCallback resultCallback_general = + // ([=](yh_581_address address, _581_Result, std::shared_ptr ) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // }); + dgh_cb_yh_3d_1.init("Camera1", "长边预焊前3D-1", 18000,2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_yh_3d_2.init("Camera2", "长边预焊前3D-2", 18200,2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_yh_3d_3.init("Camera3", "长边预焊前3D-3", 18400,2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_yh_3d_4.init("Camera4", "长边预焊前3D-4", 18600,2,1, _params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_mh_3d_1.init("Camera5", "长边满焊前3D-1", 19600,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_mh_3d_2.init("Camera6", "长边满焊前3D-2", 19800,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_mh_3d_3.init("Camera7", "长边满焊前3D-3", 20000,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_mh_3d_4.init("Camera8", "长边满焊前3D-4", 20200,2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + dgh_cb_mh_3d_1.init("Camera5", "长边满焊前3D-1", 19600,2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_2.init("Camera6", "长边满焊前3D-2", 19800,2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_3.init("Camera7", "长边满焊前3D-3", 20000,2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_4.init("Camera8", "长边满焊前3D-4", 20200,2,1, _params, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } diff --git a/src/mission/581-Dgh-CB-2/581-Dgh-CB-2.h b/src/mission/581-Dgh-CB-2/581-Dgh-CB-2.h index 9448e45..f1c409e 100644 --- a/src/mission/581-Dgh-CB-2/581-Dgh-CB-2.h +++ b/src/mission/581-Dgh-CB-2/581-Dgh-CB-2.h @@ -12,7 +12,7 @@ using namespace HDevEngineCpp; class _581_Dgh : public mission { public: - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger dgh_cb_mh_2d_1; generalTrigger dgh_cb_mh_2d_2; generalTrigger dgh_cb_mh_2d_3; @@ -27,33 +27,32 @@ public: generalTrigger dgh_cb_gy_3d_2; generalTrigger dgh_cb_gy_3d_3; generalTrigger dgh_cb_gy_3d_4; - summaryData<_581_Result> _summaryData; detParams _params; - void onConfigReloaded() { + void onConfigReloaded() { HDevEngineCpp::HDevEngine myEngine; myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); } bool initCustom() { #pragma region 注册触发器回调 满焊前2D - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - dgh_cb_mh_2d_1.init("Camera1", "长边满焊前2D-1",18800, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_mh_2d_2.init("Camera2", "长边满焊前2D-2", 19000, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_mh_2d_3.init("Camera3", "长边满焊前2D-3", 19200, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_mh_2d_4.init("Camera4", "长边满焊前2D-4", 19400, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + //generalTrigger::resultHandleCallback resultCallback_general = + // ([=](yh_581_address address, _581_Result, std::shared_ptr ) { + // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + // }); + dgh_cb_mh_2d_1.init("Camera1", "长边满焊前2D-1",18800, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_2d_2.init("Camera2", "长边满焊前2D-2", 19000, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_2d_3.init("Camera3", "长边满焊前2D-3", 19200, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_2d_4.init("Camera4", "长边满焊前2D-4", 19400, 2,1, _params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_2d_1.init("Camera5", "长边滚压后2D-1", 20400, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_gy_2d_2.init("Camera6", "长边滚压后2D-2", 20600, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_gy_2d_3.init("Camera7", "长边滚压后2D-3", 20800, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_gy_2d_4.init("Camera8", "长边滚压后2D-4", 21000, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + dgh_cb_gy_2d_1.init("Camera5", "长边滚压后2D-1", 20400, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_2d_2.init("Camera6", "长边滚压后2D-2", 20600, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_2d_3.init("Camera7", "长边滚压后2D-3", 20800, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_2d_4.init("Camera8", "长边滚压后2D-4", 21000, 2,1, _params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_3d_1.init("Camera9", "长边滚压后3D-1", 21200, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_gy_3d_2.init("Camera10", "长边滚压后3D-2", 21400, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_gy_3d_3.init("Camera11", "长边滚压后3D-3", 21600, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_cb_gy_3d_4.init("Camera12", "长边滚压后3D-4", 21800, 2,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + dgh_cb_gy_3d_1.init("Camera9", "长边滚压后3D-1", 21200, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_3d_2.init("Camera10", "长边滚压后3D-2", 21400, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_3d_3.init("Camera11", "长边滚压后3D-3", 21600, 2,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_3d_4.init("Camera12", "长边滚压后3D-4", 21800, 2,1, _params, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } diff --git a/src/mission/581-Dgh-DB-1/581-Dgh-DB-1.h b/src/mission/581-Dgh-DB-1/581-Dgh-DB-1.h index fcc1a97..079b1f9 100644 --- a/src/mission/581-Dgh-DB-1/581-Dgh-DB-1.h +++ b/src/mission/581-Dgh-DB-1/581-Dgh-DB-1.h @@ -12,7 +12,7 @@ using namespace HDevEngineCpp; class _581_Dgh : public mission { public: - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger dgh_db_yh_3d_1; generalTrigger dgh_db_yh_3d_2; @@ -25,14 +25,10 @@ public: } bool initCustom() { #pragma region 注册触发器回调 - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - dgh_db_yh_3d_1.init("Camera1", "短边预焊前3D-1", 18000,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_yh_3d_2.init("Camera2", "短边预焊前3D-2", 18200,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_mh_3d_1.init("Camera3", "短边满焊前3D-1", 18800,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_mh_3d_2.init("Camera4", "短边满焊前3D-2", 19000,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + dgh_db_yh_3d_1.init("Camera1", "短边预焊前3D-1", 18000,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_yh_3d_2.init("Camera2", "短边预焊前3D-2", 18200,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_mh_3d_1.init("Camera3", "短边满焊前3D-1", 18800,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_mh_3d_2.init("Camera4", "短边满焊前3D-2", 19000,4,1, _params, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } diff --git a/src/mission/581-Dgh-DB-2/581-Dgh-DB-2.h b/src/mission/581-Dgh-DB-2/581-Dgh-DB-2.h index 322eceb..856ea25 100644 --- a/src/mission/581-Dgh-DB-2/581-Dgh-DB-2.h +++ b/src/mission/581-Dgh-DB-2/581-Dgh-DB-2.h @@ -12,7 +12,7 @@ using namespace HDevEngineCpp; class _581_Dgh : public mission { public: - using generalTrigger = _581_Dgh_triggerTemplate; + using generalTrigger = _581_Union_triggerTemplate; generalTrigger dgh_db_mh_2d_1; generalTrigger dgh_db_mh_2d_2; @@ -29,16 +29,12 @@ public: } bool initCustom(){ #pragma region 注册触发器回调 满焊 - generalTrigger::resultHandleCallback resultCallback_general = - ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - }); - dgh_db_mh_2d_1.init("Camera1", "短边满焊前2D-1", 18400,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_mh_2d_2.init("Camera2", "短边满焊前2D-2", 18600,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_gy_2d_1.init("Camera3", "短边滚压后2D-1", 19200,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_gy_2d_2.init("Camera4", "短边滚压后2D-2", 19400,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_gy_3d_1.init("Camera5", "短边滚压后3D-1", 19600,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); - dgh_db_gy_3d_2.init("Camera6", "短边滚压后3D-2", 19800,4,1, _params, _serviceManager, bridge, generalAlgoTest, resultCallback_general); + dgh_db_mh_2d_1.init("Camera1", "短边满焊前2D-1", 18400,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_mh_2d_2.init("Camera2", "短边满焊前2D-2", 18600,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_gy_2d_1.init("Camera3", "短边滚压后2D-1", 19200,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_gy_2d_2.init("Camera4", "短边滚压后2D-2", 19400,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_gy_3d_1.init("Camera5", "短边滚压后3D-1", 19600,4,1, _params, _serviceManager, bridge, generalAlgoTest); + dgh_db_gy_3d_2.init("Camera6", "短边滚压后3D-2", 19800,4,1, _params, _serviceManager, bridge, generalAlgoTest); #pragma endregion return true; } diff --git a/src/mission/581-Mfd_djy_sd/581-Mfd.cpp b/src/mission/581-Mfd_djy_sd/581-Mfd.cpp new file mode 100644 index 0000000..c1c5f96 --- /dev/null +++ b/src/mission/581-Mfd_djy_sd/581-Mfd.cpp @@ -0,0 +1,8 @@ +#include <581-Mfd.h> + +mission* createMission() { + return new _581_Mfd(); +} +void destroyMission(mission* _mission) { + delete _mission; +} \ No newline at end of file diff --git a/src/mission/581-Mfd_djy_sd/581-Mfd.h b/src/mission/581-Mfd_djy_sd/581-Mfd.h new file mode 100644 index 0000000..cec14ce --- /dev/null +++ b/src/mission/581-Mfd_djy_sd/581-Mfd.h @@ -0,0 +1,170 @@ +#include +#include +#pragma region 算法 +#include +#include +#include +using namespace HDevEngineCpp; +static bool ShangDing(std::shared_ptr data, detParams* _detParams, yh_581_address address){; + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + std::map sqlMapData; + sqlMapData["项目"] = "上钉"; + sqlMapData["相机"] = "相机" + address.triggerAddr; + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() != 1){ + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[0].copyTo(Paint); + cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); + return false; + } + + cv::Mat Paint; + cv::Mat src1 = data->oriImgs[0]; + if (src1.channels() != 3) + cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); + else + src1.copyTo(Paint); + //处理算法 +#pragma region halcon处理 + QString singal_sign = address.triggerAddr; + int cameraNumberStr = 1; + if (singal_sign.contains("19000")) + cameraNumberStr = 2; + else if (singal_sign.contains("19200")) + cameraNumberStr = 3; + else if (singal_sign.contains("19400")) + cameraNumberStr = 4; + HalconCpp::HObject in_Image = MatToHObject(src1); + + HDevEngineCpp::HDevProcedure proc("_9_shangding"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_ProductionType", HTuple(0)); + procedureCall.SetInputCtrlParamTuple("in_CameraNumber", HTuple(cameraNumberStr)); + procedureCall.SetInputCtrlParamTuple("in_FilePath1", HTuple("./halconFiles/template/")); + procedureCall.SetInputCtrlParamTuple("in_FilePath2", HTuple("./halconFiles/base/")); + procedureCall.Execute(); + // *output(HTuple) : < / c> + // *out_Circle, 圆心坐标(y, x, radius) < / c > + // * out_Flag, 算法执行成功标志位, 0 : 算法执行失败 1 : 算法执行成功< / c> + // *out_OffsetX : 模组X轴的补偿量(mm) < / c > + // *out_OffsetY : 模组Y轴的补偿量(mm) < / c > + HTuple out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_OffsetX = procedureCall.GetOutputCtrlParamTuple("out_OffsetX"); + HTuple out_OffsetY = procedureCall.GetOutputCtrlParamTuple("out_OffsetY"); + HTuple out_ErrInfo = procedureCall.GetOutputCtrlParamTuple("out_ErrInfo"); +#pragma endregion + int outFlag = out_Flag.D(); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "camera::放钉" << "_SN::" << QString::fromStdString(data->SNcode) << ",放钉算法结果;" << out_Flag[0].D(); + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + if (outFlag == 1) { //-1为失败,无结果 + //先处理数据 + double offsetX; + double offsetY; + offsetX = 0 - out_OffsetX.D(); + offsetY = 0 - out_OffsetY.D(); + //if (singal_sign.contains("18800")) + // offsetX -= 0.2; + //else if (singal_sign.contains("19000")) { + // offsetX -= 0.15; + // offsetY += 0.1; + //} + //else if (singal_sign.contains("19400")) { + // offsetY -= 0.2; + //} + + if (abs(offsetX) >= 6000 || abs(offsetY) >= 6000){ + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123");//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送结果 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " 放钉X偏移abs(resultData[0]) >= 6000,may err,set 0"; + data->halconOK = false; + } + else { + sqlMapData["偏移X"] = offsetX; + sqlMapData["偏移Y"] = offsetY; + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(offsetX));//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(offsetY));//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + data->halconOK = true; + } + //圆及十字 + cv::circle(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D()), out_Circle[2].D(), cv::Scalar(0, 255, 0), 20); + cv::line(Paint, cv::Point(out_Circle[1].D() - 300, out_Circle[0].D()), cv::Point(out_Circle[1].D() + 300, out_Circle[0].D()), cv::Scalar(0, 255, 0), 15); + cv::line(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D() - 300), cv::Point(out_Circle[1].D(), out_Circle[0].D() + 300), cv::Scalar(0, 255, 0), 15); + + textPainter.putText(Paint, "X偏移:" + std::to_string(offsetX), cv::Point(50, 150), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "Y偏移:" + std::to_string(offsetY), cv::Point(50, 350), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "相机:" + std::to_string(cameraNumberStr), cv::Point(50, 0), cv::Scalar(0, 255, 0)); + + + } + else{ + data->halconOK = false; + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123");//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送结果 + textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); + } + + if (data->halconOK == true){ + textPainter.putText(Paint, "OK", cv::Point(50, 550), cv::Scalar(0, 255, 0)); + sqlMapData["结果"] = "OK"; + } + else{ + textPainter.putText(Paint, "NG", cv::Point(50, 500), cv::Scalar(0, 0, 255)); + sqlMapData["结果"] = "NG"; + } + data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), sqlMapData); + data->resultImgs.push_back(Paint); + return data->halconOK; +} +#pragma endregion + +class _581_Mfd : public mission { +public: + _581_Single_triggerTemplate< detParams> djy_1; + _581_Single_triggerTemplate< detParams> djy_2; + _581_Single_triggerTemplate< detParams> djy_3; + _581_Single_triggerTemplate< detParams> djy_4; + + _581_Single_triggerTemplate< detParams> sd_1; + _581_Single_triggerTemplate< detParams> sd_2; + _581_Single_triggerTemplate< detParams> sd_3; + _581_Single_triggerTemplate< detParams> sd_4; + + detParams _detParams; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); + } + bool initCustom() { +#pragma region 注册触发器回调 + djy_1.init("Camera1", "电解液1", 18000, 2, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + djy_2.init("Camera2", "电解液2", 18200, 2, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + djy_3.init("Camera3", "电解液3", 18400, 2, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + djy_4.init("Camera4", "电解液4", 18600, 2, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + + sd_1.init("Camera5", "上钉1", 18800, 1, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + sd_2.init("Camera6", "上钉2", 19000, 1, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + sd_3.init("Camera7", "上钉3", 19200, 1, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + sd_4.init("Camera8", "上钉4", 19400, 1, 1, _detParams, _serviceManager, bridge, generalAlgoTest); +#pragma endregion + return true; + } + void reloadAlgo(QByteArray& byteArray) { + + } + +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581-Mfd_djy_sd/CMakeLists.txt b/src/mission/581-Mfd_djy_sd/CMakeLists.txt new file mode 100644 index 0000000..bba2e81 --- /dev/null +++ b/src/mission/581-Mfd_djy_sd/CMakeLists.txt @@ -0,0 +1,78 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "opencv" "halcon" "handdleAI") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + ${PROJECT_ROOT_PATH}/src/core + ${PROJECT_ROOT_PATH}/src/core/handleAi + ${PROJECT_ROOT_PATH}/src/core/back + ${PROJECT_ROOT_PATH}/src/core/sql + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) +add_compile_options(/utf-8) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Sql REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ${PROJECT_ROOT_PATH}/include/qtBridge.h + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Network + Qt${QT_VERSION_MAJOR}::Sql + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " modelx end : " ${CURRENT_FOLDER}:${RUN_TIME}) +message( " header files "${HEAD_FILES}) diff --git a/src/mission/581-Mfd_yh_mh_hh/581-Mfd.cpp b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.cpp new file mode 100644 index 0000000..c1c5f96 --- /dev/null +++ b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.cpp @@ -0,0 +1,8 @@ +#include <581-Mfd.h> + +mission* createMission() { + return new _581_Mfd(); +} +void destroyMission(mission* _mission) { + delete _mission; +} \ No newline at end of file diff --git a/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h new file mode 100644 index 0000000..6e0b90e --- /dev/null +++ b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h @@ -0,0 +1,332 @@ +#include +#include +class mfd_detParams { +public: + int biaoding = 0; +}; +#pragma region 算法 +#include +#include +#include +using namespace HDevEngineCpp; +static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh_581_address address){ + std::map sqlMapData; + sqlMapData["项目"] = "上钉"; + sqlMapData["相机"] = "相机" + address.triggerAddr; + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() != 1) + { + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[0].copyTo(Paint); + cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); + return false; + } + + cv::Mat Paint; + cv::Mat src1 = data->oriImgs[0]; + if (src1.channels() != 3) + cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); + else + src1.copyTo(Paint); + //处理算法 +#pragma region halcon处理 + QString singal_sign = data->additional["触发地址"].toString(); + std::string cameraNumberStr = "1", FixtureNumber = "1"; + + if (singal_sign.contains("20000")) { + cameraNumberStr = "1"; + FixtureNumber = "1"; + } + else if (singal_sign.contains("20002")) { + cameraNumberStr = "1"; + FixtureNumber = "2"; + } + else if (singal_sign.contains("20200")) { + cameraNumberStr = "2"; + FixtureNumber = "3"; + } + else if (singal_sign.contains("20202")) { + cameraNumberStr = "2"; + FixtureNumber = "4"; + } + else if (singal_sign.contains("20400")) { + cameraNumberStr = "3"; + FixtureNumber = "5"; + } + else if (singal_sign.contains("20402")) { + cameraNumberStr = "3"; + FixtureNumber = "6"; + } + else if (singal_sign.contains("20600")) { + cameraNumberStr = "4"; + FixtureNumber = "7"; + } + else if (singal_sign.contains("20602")) { + cameraNumberStr = "4"; + FixtureNumber = "8"; + } + HalconCpp::HObject in_Image = MatToHObject(src1); + HDevEngineCpp::HDevProcedure proc("_9_manhan"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_ProductionType", _detParams->biaoding); + procedureCall.SetInputCtrlParamTuple("in_CameraNumber", HTuple(cameraNumberStr.c_str())); + procedureCall.SetInputCtrlParamTuple("in_FixtureNumber", HTuple(FixtureNumber.c_str())); + procedureCall.SetInputCtrlParamTuple("in_FilePath1", HTuple("./halconFiles/template_manHan/")); + procedureCall.SetInputCtrlParamTuple("in_FilePath2", HTuple("./halconFiles/base_manHan/")); + procedureCall.Execute(); + // *output(HTuple) : < / c> + // *out_Circle, 圆心坐标(y, x, radius) < / c > + // * out_Flag, 算法执行成功标志位, 0 : 算法执行失败 1 : 算法执行成功< / c> + // *out_OffsetX : 模组X轴的补偿量(mm) < / c > + // *out_OffsetY : 模组Y轴的补偿量(mm) < / c > + HTuple out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_OffsetX = procedureCall.GetOutputCtrlParamTuple("out_OffsetX"); + HTuple out_OffsetY = procedureCall.GetOutputCtrlParamTuple("out_OffsetY"); +#pragma endregion + int outFlag = out_Flag.D(); + //qDebug() << __FUNCTION__ << " line:" << __LINE__ << "camera::放钉" << "_SN::" << SN << ",放钉算法结果;" << out_Flag[0].D(); + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + if (outFlag == 1) { //-1为失败,无结果 + //先处理数据 + double offsetX; + double offsetY; + offsetX = 0 - out_OffsetX.D(); + offsetY = 0 - out_OffsetY.D(); + //if (singal_sign.contains("D18800")) + // offsetX -= 0.2; + //else if (singal_sign.contains("D19000")) { + // offsetX -= 0.15; + // offsetY += 0.1; + //} + //else if (singal_sign.contains("D19400")) { + // offsetY -= 0.2; + //} + if (abs(offsetX) >= 6000 || abs(offsetY) >= 6000) + { + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123");//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送结果 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " 满焊X偏移abs(resultData[0]) >= 6000,may err,set 0"; + data->halconOK = false; + } + else { + sqlMapData["偏移X"] = offsetX; + sqlMapData["偏移Y"] = offsetY; + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(offsetX));//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(offsetY));//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + data->halconOK = true; + } + //圆及十字 + cv::circle(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D()), out_Circle[2].D(), cv::Scalar(0, 255, 0), 20); + cv::line(Paint, cv::Point(out_Circle[1].D() - 300, out_Circle[0].D()), cv::Point(out_Circle[1].D() + 300, out_Circle[0].D()), cv::Scalar(0, 255, 0), 15); + cv::line(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D() - 300), cv::Point(out_Circle[1].D(), out_Circle[0].D() + 300), cv::Scalar(0, 255, 0), 15); + + textPainter.putText(Paint, "X偏移:" + std::to_string(offsetX), cv::Point(50, 150), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "Y偏移:" + std::to_string(offsetY), cv::Point(50, 350), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "相机:" + cameraNumberStr, cv::Point(50, 0), cv::Scalar(0, 255, 0)); + + + } + else{ + data->halconOK = false; + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123");//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送结果 + textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); + } + + if (data->halconOK == true) { + textPainter.putText(Paint, "OK", cv::Point(50, 550), cv::Scalar(0, 255, 0)); + sqlMapData["结果"] = "OK"; + } + else { + textPainter.putText(Paint, "NG", cv::Point(50, 500), cv::Scalar(0, 0, 255)); + sqlMapData["结果"] = "NG"; + } + data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), sqlMapData); + data->resultImgs.push_back(Paint); + + return true; +} +static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_581_address address){ + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + std::map sqlMapData; + sqlMapData["项目"] = "预焊"; + sqlMapData["相机"] = "相机" + address.triggerAddr; + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() != 1){ + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[0].copyTo(Paint); + cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2); + return false; + } + + cv::Mat Paint; + cv::Mat src1 = data->oriImgs[0]; + if (src1.channels() != 3) + cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); + else + src1.copyTo(Paint); + //处理算法 +#pragma region halcon处理 + QString singal_sign = address.triggerAddr; + std::string cameraNumberStr = "1", FixtureNumber = "1"; + if (singal_sign.contains("19600")) { + cameraNumberStr = "1"; + FixtureNumber = "1"; + } + else if (singal_sign.contains("19602")) { + cameraNumberStr = "1"; + FixtureNumber = "3"; + } + else if (singal_sign.contains("19800")) { + cameraNumberStr = "2"; + FixtureNumber = "2"; + } + else if (singal_sign.contains("19802")) { + cameraNumberStr = "2"; + FixtureNumber = "4"; + } + HDevEngineCpp::HDevProcedure proc("_9_yuhan"); + HalconCpp::HObject in_Image = MatToHObject(src1); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_ProductionType", 0); + procedureCall.SetInputCtrlParamTuple("in_Resolution", HTuple(0.00749026)); + procedureCall.SetInputCtrlParamTuple("in_CameraNumber", HTuple(cameraNumberStr.c_str())); + procedureCall.SetInputCtrlParamTuple("in_FixtureNumber", HTuple(FixtureNumber.c_str())); + procedureCall.SetInputCtrlParamTuple("in_FilePath1", HTuple("./halconFiles/yuhan_template/")); + procedureCall.SetInputCtrlParamTuple("in_FilePath2", HTuple("./halconFiles/yuhan_base/")); + procedureCall.Execute(); + // *output(HTuple) : < / c> + // *out_Circle, 圆心坐标(y, x, radius) < / c > + // * out_Flag, 算法执行成功标志位, 0 : 算法执行失败 1 : 算法执行成功< / c> + // *out_OffsetX : 模组X轴的补偿量(mm) < / c > + // *out_OffsetY : 模组Y轴的补偿量(mm) < / c > + HTuple out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_OffsetX = procedureCall.GetOutputCtrlParamTuple("out_OffsetX"); + HTuple out_OffsetY = procedureCall.GetOutputCtrlParamTuple("out_OffsetY"); +#pragma endregion + int outFlag = out_Flag.D(); + //qDebug() << __FUNCTION__ << " line:" << __LINE__ << "camera::放钉" << "_SN::" << SN << ",放钉算法结果;" << out_Flag[0].D(); + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + if (outFlag == 1) { //-1为失败,无结果 + double offsetX; + double offsetY; + offsetX = 0 - out_OffsetX.D(); + offsetY = 0 - out_OffsetY.D(); + //if (singal_sign.contains("D18800")) + // offsetX -= 0.2; + //else if (singal_sign.contains("D19000")) { + // offsetX -= 0.15; + // offsetY += 0.1; + //} + //else if (singal_sign.contains("D19400")) { + // offsetY -= 0.2; + //} + if (abs(offsetX) >= 6000 || abs(offsetY) >= 6000){ + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123");//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送结果 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " 预焊X偏移abs(resultData[0]) >= 6000,may err,set 0"; + data->halconOK = false; + } + else { + sqlMapData["偏移X"] = offsetX; + sqlMapData["偏移Y"] = offsetY; + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(offsetX));//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(offsetY));//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + data->halconOK = true; + } + //圆及十字 + cv::circle(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D()), out_Circle[2].D(), cv::Scalar(0, 255, 0), 20); + cv::line(Paint, cv::Point(out_Circle[1].D() - 300, out_Circle[0].D()), cv::Point(out_Circle[1].D() + 300, out_Circle[0].D()), cv::Scalar(0, 255, 0), 15); + cv::line(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D() - 300), cv::Point(out_Circle[1].D(), out_Circle[0].D() + 300), cv::Scalar(0, 255, 0), 15); + + textPainter.putText(Paint, "X偏移:" + std::to_string(offsetX), cv::Point(50, 150), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "Y偏移:" + std::to_string(offsetY), cv::Point(50, 350), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "相机:" + cameraNumberStr + " 孔位" + FixtureNumber, cv::Point(50, 0), cv::Scalar(0, 255, 0)); + } + else{ + data->halconOK = false; + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123");//发送偏移Y + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送结果 + textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); + } + + if (data->halconOK == true){ + textPainter.putText(Paint, "OK", cv::Point(50, 550), cv::Scalar(0, 255, 0)); + sqlMapData["结果"] = "OK"; + } + else{ + textPainter.putText(Paint, "NG", cv::Point(50, 500), cv::Scalar(0, 0, 255)); + sqlMapData["结果"] = "NG"; + } + data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), sqlMapData); + data->resultImgs.push_back(Paint); + + return true; +} +#pragma endregion +class _581_Mfd : public mission { +public: + _581_Single_triggerTemplate< mfd_detParams> yh_1; + _581_Single_triggerTemplate< mfd_detParams> yh_2; + + _581_Single_triggerTemplate< mfd_detParams> mh_1; + _581_Single_triggerTemplate< mfd_detParams> mh_2; + _581_Single_triggerTemplate< mfd_detParams> mh_3; + _581_Single_triggerTemplate< mfd_detParams> mh_4; + + _581_Union_triggerTemplate< detParams> hh_2D; + _581_Union_triggerTemplate< detParams> hh_3D; + + mfd_detParams _params; + + detParams _detParams; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); + } + bool initCustom() { +#pragma region 注册触发器回调 + yh_1.init("Camera1", "预焊1", 19600, 2, 1, _params, _serviceManager, bridge, YuHan); + yh_2.init("Camera2", "预焊2", 19800, 2, 1, _params, _serviceManager, bridge, YuHan); + + mh_1.init("Camera3", "满焊1", 20000, 2, 1, _params, _serviceManager, bridge, ManHan); + mh_2.init("Camera4", "满焊2", 20200, 2, 1, _params, _serviceManager, bridge, ManHan); + mh_3.init("Camera5", "满焊3", 20400, 2, 1, _params, _serviceManager, bridge, ManHan); + mh_4.init("Camera6", "满焊4", 20600, 2, 1, _params, _serviceManager, bridge, ManHan); + + hh_2D.init("Camera7", "焊后2d", 20800, 2, 1, _detParams, _serviceManager, bridge, generalAlgoTest); + hh_3D.init("Camera8", "焊后3d", 21000, 2, 1, _detParams, _serviceManager, bridge, generalAlgoTest); +#pragma endregion + return true; + } + + + //9600 + +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt b/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt new file mode 100644 index 0000000..bba2e81 --- /dev/null +++ b/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt @@ -0,0 +1,78 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "opencv" "halcon" "handdleAI") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + ${PROJECT_ROOT_PATH}/src/core + ${PROJECT_ROOT_PATH}/src/core/handleAi + ${PROJECT_ROOT_PATH}/src/core/back + ${PROJECT_ROOT_PATH}/src/core/sql + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) +add_compile_options(/utf-8) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Sql REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ${PROJECT_ROOT_PATH}/include/qtBridge.h + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Network + Qt${QT_VERSION_MAJOR}::Sql + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " modelx end : " ${CURRENT_FOLDER}:${RUN_TIME}) +message( " header files "${HEAD_FILES}) diff --git a/src/mission/581-Ruke/581-Ruke.cpp b/src/mission/581-Ruke/581-Ruke.cpp new file mode 100644 index 0000000..2c76968 --- /dev/null +++ b/src/mission/581-Ruke/581-Ruke.cpp @@ -0,0 +1,8 @@ +#include <581-Ruke.h> + +mission* createMission() { + return new _581_Ruke(); +} +void destroyMission(mission* _mission) { + delete _mission; +} \ No newline at end of file diff --git a/src/mission/581-Ruke/581-Ruke.h b/src/mission/581-Ruke/581-Ruke.h new file mode 100644 index 0000000..0327485 --- /dev/null +++ b/src/mission/581-Ruke/581-Ruke.h @@ -0,0 +1,38 @@ +#include +#include + +#pragma region 算法 +#include +#include +#include +using namespace HDevEngineCpp; + +#pragma endregion + +class _581_Ruke : public mission { +public: + _581_Union_triggerTemplate ruke_cam1_3; + _581_Union_triggerTemplate ruke_cam2_1; + _581_Union_triggerTemplate ruke_cam3_3; + _581_Union_triggerTemplate ruke_cam4_1; + detParams _params; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); + } + bool initCustom() { +#pragma region 注册触发器回调 + ruke_cam1_3.init("Camera1","入壳相机1下",18000, 2, 3, _params,_serviceManager, bridge, generalAlgoTest); + ruke_cam2_1.init("Camera2", "入壳相机2左",18200 , 2, 1, _params, _serviceManager, bridge, generalAlgoTest); + ruke_cam3_3.init("Camera3", "入壳相机3上",18400, 2, 3, _params, _serviceManager, bridge, generalAlgoTest); + ruke_cam4_1.init("Camera4", "入壳相机4右",18600, 2, 1, _params, _serviceManager, bridge, generalAlgoTest); +#pragma endregion + return true; + } +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581-Ruke/CMakeLists.txt b/src/mission/581-Ruke/CMakeLists.txt new file mode 100644 index 0000000..76bbff3 --- /dev/null +++ b/src/mission/581-Ruke/CMakeLists.txt @@ -0,0 +1,77 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "opencv" "halcon" "handdleAI") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + ${PROJECT_ROOT_PATH}/src/core + ${PROJECT_ROOT_PATH}/src/core/handleAi + ${PROJECT_ROOT_PATH}/src/core/back + ${PROJECT_ROOT_PATH}/src/core/sql + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) +add_compile_options(/utf-8) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ${PROJECT_ROOT_PATH}/include/qtBridge.h + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Network + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " modelx end : " ${CURRENT_FOLDER}:${RUN_TIME}) +message( " header files "${HEAD_FILES}) diff --git a/subModule/Hd_CameraModule_3DKeyence/CMakeLists.txt b/subModule/Hd_CameraModule_3DKeyence/CMakeLists.txt new file mode 100644 index 0000000..cb49af5 --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence/CMakeLists.txt @@ -0,0 +1,71 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "keyence3D" "opencv") +foreach(child ${DLL_NAMES}) + + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) + + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "./*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " model end : " ${CURRENT_FOLDER}:${RUN_TIME}) diff --git a/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp b/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp new file mode 100644 index 0000000..526ea93 --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp @@ -0,0 +1,606 @@ +#include "Hd_CameraModule_3DKeyence.h" +#include +#include +#include +#include +#include + +int G_xImageSize = 0; // Number of X points. +int G_yImageSize = 0; // Number of Y lines. +//const int MAX_LJXA_XDATANUM = 3200; +//const unsigned int BUFFER_FULL_COUNT = 30000; +// +//int _imageAvailable[MAX_LJXA_DEVICENUM] = { 0 }; +//unsigned short* _luminanceBuf[MAX_LJXA_DEVICENUM] = { 0 }; +//unsigned short* _heightBuf[MAX_LJXA_DEVICENUM] = { 0 }; +//int _lastImageSizeHeight[MAX_LJXA_DEVICENUM]; +int imgTakeNum = 0, imgTarget = 1; +int imgIndex = 0; +QMutex* m_mutex = nullptr; +std::mutex bufferMutex; +QQueue< cv::Mat> heightMatS;//高度图 +QQueue luminanceMatS;//灰度图 +//data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。 +bool ifBreak = false; +//ifRunning减少ifBreak的判断;"rest_newProductIn"时,Logic_camera_thread框架会结束未处理完的相相机取图 +bool ifRunning = false; +QString byteArrayToUnicode(const QByteArray array) { + + // state用于保存转换状态,它的成员invalidChars,可用来判断是否转换成功 + // 如果转换成功,则值为0,如果值大于0,则说明转换失败 + QTextCodec::ConverterState state; + // 先尝试使用utf-8的方式把QByteArray转换成QString + QString text = QTextCodec::codecForName("UTF-8")->toUnicode(array.constData(), array.size(), &state); + // 如果转换时无效字符数量大于0,说明编码格式不对 + if (state.invalidChars > 0) + { + // 再尝试使用GBK的方式进行转换,一般就能转换正确(当然也可能是其它格式,但比较少见了) + text = QTextCodec::codecForName("GBK")->toUnicode(array); + } + return text; +} + +bool JumpFlag = false; +int yCounts; +void myCallbackFunc(LJX8IF_PROFILE_HEADER* pProfileHeaderArray, WORD* pHeightProfileArray, WORD* pLuminanceProfileArray, DWORD dwLuminanceEnable, DWORD dwProfileDataCount, DWORD dwCount, DWORD dwNotify, DWORD dwUser) +{ + try + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " --> Enter callback function"; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwProfileDataCount = " << dwProfileDataCount; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwCount = " << dwCount; + std::cout << "dwCount->" << dwCount <<" dwProfileDataCount"<< dwProfileDataCount << "dwNotify = " << dwNotify<< std::endl; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwNotify = " << dwNotify; + //if (dwCount < 1000)return; + /* if ((dwNotify != 0) || (dwNotify & 0x10000) != 0) + { + return; + }*/ + std::lock_guard lock(bufferMutex); + if (dwCount == 0) + { + return; + } + if (_imageAvailable[dwUser] == 1) + { + return; + } + + + + // _heightBuf 代表的含义:程序里的高度缓存区,pHeightProfileArray 回调函数里的数据 + // 此处崩溃的可能性:xImageSize 配置文件中设置的值和3D相机调试软件设置的值不一致,会崩溃。 + if (JumpFlag) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "JumpFlag"; + return; + } + if (_heightBuf[dwUser] == NULL) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_heightBuf[dwUser] == NULL"; + _heightBuf[dwUser] = (unsigned short*)malloc(G_yImageSize * MAX_LJXA_XDATANUM * 2); + //return; + } + if (pHeightProfileArray == NULL) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pHeightProfileArray== NULL"; + return; + } + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_heightBuf[dwUser]: " << _heightBuf[dwUser]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pHeightProfileArray: " << pHeightProfileArray; + + //判断内存是否重叠 + if (_heightBuf[dwUser] <= pHeightProfileArray || (unsigned short*)_heightBuf[dwUser] >= (WORD*)pHeightProfileArray + dwProfileDataCount * dwCount * 2) + { + memcpy(&_heightBuf[dwUser][0], pHeightProfileArray, dwProfileDataCount * dwCount * 2); + } + else + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "first memcpy _heightBuf error"; + if (_heightBuf[dwUser] != NULL) + { + free(_heightBuf[dwUser]); + _heightBuf[dwUser] = NULL; + } + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " memcpy _heightBuf again "; + _heightBuf[dwUser] = (unsigned short*)malloc(yCounts * MAX_LJXA_XDATANUM * 2); + memcpy(&_heightBuf[dwUser][0], pHeightProfileArray, dwProfileDataCount * dwCount * 2); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Second memcpy _heightBuf success "; + + } + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_luminanceBuf[dwUser]: " << _luminanceBuf[dwUser]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pLuminanceProfileArray: " << pLuminanceProfileArray; + if (dwLuminanceEnable == 1) + { + if (_luminanceBuf[dwUser] == NULL) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_luminanceBuf[dwUser]== NULL"; + //return; + _luminanceBuf[dwUser] = (unsigned short*)malloc(G_yImageSize * MAX_LJXA_XDATANUM * 2); + } + if (_luminanceBuf[dwUser] <= pLuminanceProfileArray || (unsigned short*)_luminanceBuf[dwUser] >= (WORD*)pLuminanceProfileArray + dwProfileDataCount * dwCount * 2) + memcpy(&_luminanceBuf[dwUser][0], pLuminanceProfileArray, dwProfileDataCount * dwCount * 2); + else + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "memcpy _luminanceBuf error"; + } + _imageAvailable[dwUser] = 1; // 图像获取成功 dwUser 和 deviceId 一致 + _lastImageSizeHeight[dwUser] = dwCount; // 扫描的行数, dwCount 和 yImageSize 一致 + } + catch (std::exception e) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " --> execute callback function error"; + } +} + +int Hd_CameraModule_3DKeyence::LJXA_ACQ_OpenDevice(int lDeviceId, LJX8IF_ETHERNET_CONFIG* EthernetConfig, int HighSpeedPortNo) +{ + int errCode = LJX8IF_EthernetOpen(lDeviceId, EthernetConfig); + + _ethernetConfig[lDeviceId] = *EthernetConfig; + _highSpeedPortNo[lDeviceId] = HighSpeedPortNo; + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Open device ! errCode:" << errCode; + return errCode; +} + +void Hd_CameraModule_3DKeyence::LJXA_ACQ_CloseDevice(int lDeviceId) +{ + LJX8IF_FinalizeHighSpeedDataCommunication(lDeviceId); + LJX8IF_CommunicationClose(lDeviceId); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Close device!"; +} + + +bool Hd_CameraModule_3DKeyence::decodeInitData(QByteArray byteArray,QVector &vector_data) +{ + while (!byteArray.isEmpty()) + { + int type = 0; + QByteArray m_type = byteArray.mid(0,4); + memcpy((void*)&type,(void*)m_type.data(), 4); + byteArray.remove(0,4); + + int len = 0; + QByteArray m_len = byteArray.mid(0,4); + memcpy((void*)&len,(void*)m_len.data(), 4); + byteArray.remove(0,4); + + QByteArray mm_data = byteArray.mid(0,len); + vector_data.append(mm_data); + byteArray.remove(0,len); + } + return true; +} + +Hd_CameraModule_3DKeyence* create() +{ + qDebug() << __FUNCTION__ << "line:" << __LINE__ << " Hd_CameraModule_3DKeyence create success!" ; + return new Hd_CameraModule_3DKeyence; +} + +void destory(Hd_CameraModule_3DKeyence * ptr) +{ + if (ptr) + { + delete ptr; + ptr = nullptr; + } + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Hd_CameraModule_3DKeyence destory success!"; +} + +Hd_CameraModule_3DKeyence::Hd_CameraModule_3DKeyence() +{ + m_mutex = new QMutex; +} + + +Hd_CameraModule_3DKeyence::~Hd_CameraModule_3DKeyence() +{ + if (isopen) + { + isopen = false; + + // Stop HighSpeed + errCode = LJX8IF_StopHighSpeedDataCommunication(deviceId); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Stop HighSpeed errCode:" << errCode; + + LJXA_ACQ_CloseDevice(deviceId); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << " CloseDevice success!"; + if (heightImage) + { + free(heightImage); + + } + if (luminanceImage) + { + free(luminanceImage); + } + } + + // Free memory + if (_heightBuf[deviceId] != NULL) + { + free(_heightBuf[deviceId]); + } + + if (_luminanceBuf[deviceId] != NULL) + { + free(_luminanceBuf[deviceId]); + } + + if (startReq_ptr) + { + delete startReq_ptr; + startReq_ptr = nullptr; + } + + if (profileInfo_ptr) + { + delete profileInfo_ptr; + profileInfo_ptr = nullptr; + } + + if (setParam_Ptr) + { + delete setParam_Ptr; + setParam_Ptr = nullptr; + } + + if (getParam_Ptr) + { + delete getParam_Ptr; + getParam_Ptr = nullptr; + } + if (m_mutex) + { + delete m_mutex; + m_mutex = nullptr; + } + qDebug() << __FUNCTION__ << "line:" << __LINE__ << " delete success!"; +} + +bool Hd_CameraModule_3DKeyence::readData(std::vector &mats,QByteArray &data) +{ + Q_UNUSED(data); + + QMutexLocker locker(m_mutex); + if (luminanceMatS.empty() || heightMatS.empty()) + { + qDebug() << " [Error] " << " srcImage is null"; + return false; + } + for (int i = 0; i < imgTarget; i++) { + if (heightMatS.size() >= 1 && luminanceMatS.size() >= 1) { + mats.push_back(luminanceMatS.dequeue()); + mats.push_back(heightMatS.dequeue()); + } + else { + mats.push_back(cv::Mat(G_xImageSize, G_yImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + mats.push_back(cv::Mat(G_xImageSize, G_yImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + } + } + imgTakeNum = 0; + qCritical() << " [info] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData,deviceId" << deviceId << " imgIndex" << imgIndex; + return true; +} + +bool Hd_CameraModule_3DKeyence::writeData(std::vector &mat,QByteArray &data) +{ + if (data == "clearCahce") { + QMutexLocker locker(m_mutex); + heightMatS.clear(); + luminanceMatS.clear(); + } + //2024.02.18更新,相机对应的读SN信号时,表示新产品进入,设置初始值 + //if (data == "rest_newProductIn") + //{ + // //根据实际项目,设置初始值:曝光、增益,ROI区域等 + // /*{ + // if (expourseTimeList.size() > 0) + // SetExposureTime(expourseTimeList[0]); + // if (gainList.size() > 0) + // SetGain(gainList[0]); + // } + // getImageNum = 0;*/ + // if (luminanceMatS.size() > 0 || heightMatS.size() > 0) + // { + // m_mutex->lock(); + // luminanceMatS.clear(); + // heightMatS.clear(); + // m_mutex->unlock(); + // std::cout << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << camera_name.toStdString() << std::endl; + // qWarning() << __FUNCTION__ << " line: " << __LINE__ << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << camera_name; + // } + // if (ifRunning == true) + // { + // ifBreak = true; + // Sleep(10); + // } + // imgIndex = 0; + // //getImageNum = 0; + // return true; + //} + + + return true; +} + +//传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... +bool Hd_CameraModule_3DKeyence::initParas(QByteArray& initData) +{ + EthernetConfig.wPortNo = 24691; + QByteArrayList valueList = initData.split('+'); + camera_name = valueList[0]; + //deviceId = valueList[0].toInt(); //相机头序号 + if (valueList.size() > 1) + for (int i = 0; i < valueList.size(); i++) + { + QString valuei = byteArrayToUnicode(valueList[i]); + if (valuei.contains("ip")) + { + //ip#192.168.0.1 + QStringList valueL = valuei.split("#"); + if (valueL.size() == 2) + { + QStringList valueL1 = valueL[1].split("."); + if (valueL1.size() == 4) + { + EthernetConfig.abyIpAddress[0] = valueL1.at(0).toInt(); + EthernetConfig.abyIpAddress[1] = valueL1.at(1).toInt(); + EthernetConfig.abyIpAddress[2] = valueL1.at(2).toInt(); + EthernetConfig.abyIpAddress[3] = valueL1.at(3).toInt(); + } + } + } + if (valuei.contains("deviceId")) + { + QStringList valueL = valuei.split('#'); + if (valueL.size() == 2) + { + deviceId = valueL[1].toInt(); + } + } + if (valuei.contains("port")) + { + //port#24691 + QStringList valueL = valuei.split('#'); + if (valueL.size() == 2) + { + EthernetConfig.wPortNo = valueL[1].toInt(); + } + } + if (valuei.contains("xImageSize")) + { + //xImageSize#1600 + QStringList valueL = valuei.split('#'); + if (valueL.size() == 2) + { + xImageSize = valueL[1].toInt(); + G_xImageSize = valueL[1].toInt(); + } + } + if (valuei.contains("yImageSize")) + { + //yImageSize#2000 + QStringList valueL = valuei.split('#'); + if (valueL.size() == 2) + { + yImageSize = valueL[1].toInt(); + G_yImageSize = valueL[1].toInt(); + } + } + if (valuei.contains("y_pitch_um")) + { + //y_pitch_um#40 + QStringList valueL = valuei.split('#'); + if (valueL.size() == 2) + { + y_pitch_um = valueL[1].toDouble(); + } + } + if (valuei.contains("imgTarget")) + { + QStringList valueL = valuei.split('#'); + if (valueL.size() == 2) + { + imgTarget = valueL[1].toInt(); + } + } + } + + yCounts = yImageSize; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " camera_name:" << camera_name << " paras init is success!"; + + // 初始化申请空间 20230214 + startReq_ptr = new LJX8IF_HIGH_SPEED_PRE_START_REQ; + profileInfo_ptr = new LJX8IF_PROFILE_INFO; + startReq_ptr->bySendPosition = 2; + + setParam_Ptr = new LJXA_ACQ_SETPARAM; + getParam_Ptr = new LJXA_ACQ_GETPARAM; + + setParam_Ptr->y_linenum = yImageSize; + setParam_Ptr->y_pitch_um = y_pitch_um; + setParam_Ptr->timeout_ms = timeout_ms; + setParam_Ptr->use_external_batchStart = use_external_batchStart; + + // Allocate user memory + heightImage = (unsigned short*)malloc(sizeof(unsigned short) * xImageSize * yImageSize); + luminanceImage = (unsigned short*)malloc(sizeof(unsigned short) * xImageSize * yImageSize); + + errCode = LJXA_ACQ_OpenDevice(deviceId, &EthernetConfig, HighSpeedPortNo); + if ( errCode != LJX8IF_RC_OK ) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Failed to open device "; + //Free user memory + if ( heightImage ) + { + free(heightImage); + } + + if ( luminanceImage ) + { + free(luminanceImage); + } + return false; + } + + isopen = true; + + // Allocate memory + _heightBuf[deviceId] = (unsigned short*)malloc(yImageSize * MAX_LJXA_XDATANUM * 2); + if (_heightBuf[deviceId] == NULL) + { + return LJX8IF_RC_ERR_NOMEMORY; + } + + _luminanceBuf[deviceId] = (unsigned short*)malloc(yImageSize * MAX_LJXA_XDATANUM * 2); + if (_luminanceBuf[deviceId] == NULL) + { + return LJX8IF_RC_ERR_NOMEMORY; + } + + // Initialize + if (!InitHighSpeed()) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " InitHighSpeed error! " ; + } + return true; +} +bool Hd_CameraModule_3DKeyence::InitHighSpeed() +{ + try + { + if ( startReq_ptr == nullptr ) + { + startReq_ptr = new LJX8IF_HIGH_SPEED_PRE_START_REQ; + startReq_ptr->bySendPosition = 2; + qWarning() << __FUNCTION__ << " line: " << __LINE__ << " startReq_ptr is null! "; + } + if ( profileInfo_ptr == nullptr ) + { + profileInfo_ptr = new LJX8IF_PROFILE_INFO; + qWarning() << __FUNCTION__ << " line: " << __LINE__ << " profileInfo_ptr is null! "; + } + errCode = LJX8IF_InitializeHighSpeedDataCommunicationSimpleArray(deviceId, &_ethernetConfig[deviceId], _highSpeedPortNo[deviceId], &myCallbackFunc, yImageSize, deviceId); // 初始化高速通讯 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode:" << errCode; + errCode = LJX8IF_PreStartHighSpeedDataCommunication(deviceId, startReq_ptr, profileInfo_ptr); // 预开始启动高速通信,作用 做预连接 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode:" << errCode; + + // zUnit + errCode = LJX8IF_GetZUnitSimpleArray(deviceId, &zUnit); + if (errCode != 0 || zUnit == 0) + { + qCritical() << __FUNCTION__ << " line:" << __LINE__ << " Failed to acquire zunit! "; + return false; + } + errCode = LJX8IF_StartHighSpeedDataCommunication(deviceId); // 正式开始高速通讯 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode: " << errCode; + + //Start HighSpeed + _imageAvailable[deviceId] = 0; + _lastImageSizeHeight[deviceId] = 0; + } + catch (const QString ev) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " ev: " << ev; + return false; + } + return true; + +} + +bool Hd_CameraModule_3DKeyence::run() +{ + + ifRunning = true; + ifBreak = false; + if ( !isopen ) + { + qCritical() << __FUNCTION__ << " line:" << __LINE__ << " device is not opened! "; + return false; + } + + try + { + while (imgTakeNum != imgTarget) + { + int timeOutCnt = 0; + while (_imageAvailable[deviceId] != 1 && timeOutCnt < 1200) + { + timeOutCnt++; + QThread::msleep(10); + } + if (timeOutCnt >= 1200) + { + heightMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + luminanceMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + imgTakeNum++; + qDebug() << "imgGetERROR insert blank img cameraID:" << camera_name; + continue; + } + + std::lock_guard lock(bufferMutex); + _getParam[deviceId].luminance_enabled = profileInfo_ptr->byLuminanceOutput; + _getParam[deviceId].x_pointnum = profileInfo_ptr->wProfileDataCount; + _getParam[deviceId].y_linenum_acquired = _lastImageSizeHeight[deviceId]; + _getParam[deviceId].x_pitch_um = profileInfo_ptr->lXPitch / 100.0f; + _getParam[deviceId].y_pitch_um = y_pitch_um; + _getParam[deviceId].z_pitch_um = zUnit / 100.0f; + + *getParam_Ptr = _getParam[deviceId]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " getPara Finished: "; + int xDataNum = _getParam[deviceId].x_pointnum; + + unsigned short* dwHeightBuf = (unsigned short*)&_heightBuf[deviceId][0]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " dwHeightBuf Init Finished: "; + memcpy(heightImage, dwHeightBuf, xDataNum * yImageSize * 2); + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Height Img memcpy Finished: "; + std::vectorpoits(xDataNum * yImageSize * 2, 0); + if (_getParam[deviceId].luminance_enabled > 0) + { + unsigned short* dwLuminanceBuf = (unsigned short*)&_luminanceBuf[deviceId][0]; + memcpy(luminanceImage, dwLuminanceBuf, xDataNum * yImageSize * 2); + } + // Free memory + if (_heightBuf[deviceId] != NULL) + { + free(_heightBuf[deviceId]); + _heightBuf[deviceId] = NULL; + } + + if (_luminanceBuf[deviceId] != NULL) + { + free(_luminanceBuf[deviceId]); + _luminanceBuf[deviceId] = NULL; + } + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Free memory Finished: "; + + m_mutex->lock(); + cv::Mat luminanceMat(yImageSize, xImageSize, CV_16UC1, luminanceImage); + cv::normalize(luminanceMat, luminanceMat, 0, 255, cv::NORM_MINMAX); + cv::convertScaleAbs(luminanceMat, luminanceMat); + luminanceMatS.enqueue(luminanceMat); + + cv::Mat heightImg; + cv::Mat(yImageSize, xImageSize, CV_16UC1, heightImage).copyTo(heightImg); + heightMatS.enqueue(heightImg); + m_mutex->unlock(); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " success to acquire 3d image! camera_name: " << camera_name; + //Start HighSpeed + _imageAvailable[deviceId] = 0; + _lastImageSizeHeight[deviceId] = 0; + imgTakeNum++; + } + qDebug() << "take2 Finish"; + return true; + } + catch (QString ev) + { + qCritical() << __FUNCTION__ << " line: " << __LINE__ << " ev: " << ev; + return false; + } +} diff --git a/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.h b/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.h new file mode 100644 index 0000000..ccdf9fc --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.h @@ -0,0 +1,108 @@ +#ifndef Hd_CameraModule_3DKeyence_H +#define Hd_CameraModule_3DKeyence_H + +#include +#include +#include +#include +#include + +#include "LJX8_IF.h" +#include "LJX8_ErrorCode.h" + +#include + +#pragma comment(lib, "winmm.lib") +#pragma execution_character_set("utf-8") + +typedef struct { + int y_linenum; + float y_pitch_um; + int timeout_ms; + int use_external_batchStart; +} LJXA_ACQ_SETPARAM; + +typedef struct { + int luminance_enabled; + int x_pointnum; + int y_linenum_acquired; + float x_pitch_um; + float y_pitch_um; + float z_pitch_um; +} LJXA_ACQ_GETPARAM; + + +const int MAX_LJXA_DEVICENUM = 6; +const int MAX_LJXA_XDATANUM = 3200; +const unsigned int BUFFER_FULL_COUNT = 30000; + +static int _imageAvailable[MAX_LJXA_DEVICENUM] = { 0 }; +static unsigned short* _luminanceBuf[MAX_LJXA_DEVICENUM] = { 0 }; +static unsigned short* _heightBuf[MAX_LJXA_DEVICENUM] = { 0 }; +static int _lastImageSizeHeight[MAX_LJXA_DEVICENUM]; + +class Hd_CameraModule_3DKeyence :public dsModuleBase +{ +public: + Hd_CameraModule_3DKeyence(); + virtual ~Hd_CameraModule_3DKeyence(); + //从类中读数据到实例对象 + bool readData(std::vector& mats, QByteArray& data); + //实例对象把数据写入到类 + bool writeData(std::vector& mat, QByteArray& data); + bool initParas(QByteArray& initData); + bool run(); + + int LJXA_ACQ_OpenDevice(int lDeviceId, LJX8IF_ETHERNET_CONFIG* EthernetConfig, int HighSpeedPortNo); + //int LJXA_ACQ_StartAsync(int lDeviceId, LJXA_ACQ_SETPARAM* setParam); + //int LJXA_ACQ_AcquireAsync(int lDeviceId, unsigned short* heightImage, unsigned short* luminanceImage, LJXA_ACQ_SETPARAM* setParam, LJXA_ACQ_GETPARAM* getParam); + void LJXA_ACQ_CloseDevice(int lDeviceId); + + bool decodeInitData(QByteArray byteArray, QVector& vector_data); + bool InitHighSpeed(); +private: + //int LJXA_ACQ_Acquire(int lDeviceId, unsigned short* heightImage, unsigned short* luminanceImage, LJXA_ACQ_SETPARAM* setParam, LJXA_ACQ_GETPARAM* getParam); + LJX8IF_HIGH_SPEED_PRE_START_REQ* startReq_ptr = nullptr; + LJX8IF_PROFILE_INFO* profileInfo_ptr = nullptr; + + // Static variable + LJX8IF_ETHERNET_CONFIG _ethernetConfig[MAX_LJXA_DEVICENUM]; + int _highSpeedPortNo[MAX_LJXA_DEVICENUM]; + + LJXA_ACQ_GETPARAM _getParam[MAX_LJXA_DEVICENUM]; + + int deviceId = 0; // Set "0" if you use only 1 head. + int xImageSize = 0; // Number of X points. + int yImageSize = 0; // Number of Y lines. + float y_pitch_um = 0; // Data pitch of Y data. (e.g. your encoder setting) + int timeout_ms = 0; // Timeout value for the acquiring image (in milisecond). + int use_external_batchStart = 1; // Set "1" if you controll the batch start timing externally. (e.g. terminal input) 0内部触发,1外部触发 + std::string outputFilePath1 = "sample_height.csv"; + std::string outputFilePath2 = "sample_height.tif"; + std::string outputFilePath3 = "sample_luminance.tif"; + + //std::vector< cv::Mat> vector_mat; + unsigned short zUnit = 0; + + unsigned short* heightImage = nullptr; // Height image + unsigned short* luminanceImage = nullptr; // Luminance image + + LJXA_ACQ_SETPARAM* setParam_Ptr = nullptr; + LJXA_ACQ_GETPARAM* getParam_Ptr = nullptr; + int HighSpeedPortNo = 24692; // Port number for high-speed communication + bool isopen = false; + int errCode; + + LJX8IF_ETHERNET_CONFIG EthernetConfig; + + QString camera_name; // 相机名称 + int recontimeout_ms = 3000; +}; + +extern "C" +{ + Q_DECL_EXPORT Hd_CameraModule_3DKeyence* create(); + Q_DECL_EXPORT void destory(Hd_CameraModule_3DKeyence* ptr); +} + +#endif // HD_MVCAMERA_MODULE_H diff --git a/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp b/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp index a5a4047..1ef8130 100644 --- a/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp +++ b/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp @@ -77,7 +77,7 @@ bool Hd_VirtualCamera::run()//����� } else { vector mats; - mats.push_back(cv::Mat(15000,15000,CV_8UC3,cv::Scalar(0,0,255))); + mats.push_back(cv::Mat(4096,3200,CV_8UC3,cv::Scalar(0,255,0))); queuePic.enqueue(mats); } n_mutex->unlock();