diff --git a/include/qtBridge.h b/include/qtBridge.h index a75ea8f..2a2a177 100644 --- a/include/qtBridge.h +++ b/include/qtBridge.h @@ -68,5 +68,8 @@ signals: void runCommand_addBtn(const QString& btnName, const QString& tip, const QString& uuid); void runCommand_addPlcValueViewer(const QString& groupName,std::vector> viewerNameAndAddress); void runCommand_refeshPlcValueViewer(int address,int value); + + //性能监测 + void sendTriggerManagerLoopData(int loopCounterPerMin,int maxInterval); }; #pragma once \ No newline at end of file diff --git a/include/sxGlobal.h b/include/sxGlobal.h index c725f9f..5c043f0 100644 --- a/include/sxGlobal.h +++ b/include/sxGlobal.h @@ -5,6 +5,7 @@ #include #include #pragma region 基础函数 + #define CATCH_EXCEPTIONS \ catch (HDevEngineCpp::HDevEngineException& ex) { \ std::cout << "HDevEngineException: " << ex.Message() << std::endl; \ diff --git a/include/yhGlobal.h b/include/yhGlobal.h index f84e450..fabc3ea 100644 --- a/include/yhGlobal.h +++ b/include/yhGlobal.h @@ -231,7 +231,7 @@ public: 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() + "清零"); + _serviceManager->_triggerManager->writeShort("D" + QByteArray::number(address[0].completeAddr.toInt() + i * 2) + "_0"); }, "D" + address[0].completeAddr.toStdString() + "清零"); } for (int i = 0; i < address.size(); i++) { _serviceManager->_triggerManager->registerPlcValueViewer(viewerNameIN + "_" + QString::number(i), @@ -246,7 +246,7 @@ public: } //获取图片并进行检测 void evaluate(int batteryOffset, QByteArray& byteArray) { - _serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_1");//完成信号 固定只发在第0位 + _serviceManager->_triggerManager->writeShort("D" + QByteArray::number(address[0].completeAddr.toInt() + batteryOffset) + "_1");//完成信号 根据偏移发送 std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, false, -1); auto camera = _serviceManager->_cameraManager->getCamera(cameraName); camera->clearCache(); diff --git a/src/Core/CMakeLists.txt b/src/Core/CMakeLists.txt index 5ab2d26..04689e6 100644 --- a/src/Core/CMakeLists.txt +++ b/src/Core/CMakeLists.txt @@ -56,8 +56,8 @@ FILE(GLOB_RECURSE APP_UI_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.ui") FILE(GLOB_RECURSE APP_UI_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.cc") INCLUDE_DIRECTORIES(${CMAEK_CURRENT_BINARY_DIR}) -set(RESOURCES_DIR ${CMAKE_SOURCE_DIR}"/resources/resources.qrc") -set(WIN_RC_DIR ${CMAKE_SOURCE_DIR}"/resources/ff.rc") +set(RESOURCES_DIR ${CMAKE_SOURCE_DIR}/resources/resources.qrc) +set(WIN_RC_DIR ${CMAKE_SOURCE_DIR}/resources/ff.rc) # 生成动态库(DLL/.so/.dylib) FILE(GLOB CORE_HEADER_FILES "${PROJECT_ROOT_PATH}/include/core/*.h") diff --git a/src/Core/back/triggerManager.cpp b/src/Core/back/triggerManager.cpp index 4cc3c11..d479160 100644 --- a/src/Core/back/triggerManager.cpp +++ b/src/Core/back/triggerManager.cpp @@ -33,11 +33,11 @@ void triggerManager::run(){ if(connectHost() == false) return; QThread::msleep(1000); - QElapsedTimer heartTimer, loopCounterCollectTimer; - int loopCounter = 0; - while (runFlag){ + QElapsedTimer heartTimer, loopCounterCollectTimer,loopIntervalTimer; + int loopCounter = 0,maxIntervalLog = 0,interval = 0; + loopIntervalTimer.start(); + while (runFlag){ reciveCommond(); - QThread::msleep(sleepIntervalMS); //心跳 if (heartTimer.elapsed()> heartBeatIntervalMS) { sendFinsMsg(heartBeatCmds[heartBeatCmdCnt++]); @@ -45,12 +45,15 @@ void triggerManager::run(){ heartBeatCmdCnt = 0; heartTimer.start(); } - // if (loopCounterCollectTimer.elapsed() > 1000) { - //qDebug() << "loop counter:" << loopCounter << " time:" << loopCounterCollectTimer.elapsed(); - // loopCounter = 0; - // loopCounterCollectTimer.start(); - // } - // loopCounter++; + if (loopCounterCollectTimer.elapsed() > 3000) { + emit bridge->sendTriggerManagerLoopData(loopCounter / 3, maxIntervalLog); + maxIntervalLog = 0; + loopCounter = 0; + loopCounterCollectTimer.start(); + } + loopCounter++; + QThread::msleep(qMax(0, sleepIntervalMS - (int)loopIntervalTimer.elapsed())); + maxIntervalLog = qMax(maxIntervalLog, (int)loopIntervalTimer.restart()); } } bool triggerManager::connectHost(){ diff --git a/src/Core/back/triggerManager.h b/src/Core/back/triggerManager.h index 830d162..0ee9189 100644 --- a/src/Core/back/triggerManager.h +++ b/src/Core/back/triggerManager.h @@ -238,7 +238,7 @@ public: std::map> unionTriggerCallbackFuncs; //联合条件的触发器注册 bool registerUnionCallback(std::vector> triggerAddressAndValue, - conditionMode mode, + conditionMode mode, uniontriggerCallback func, std::string funcName = "") { QMutexLocker locer(&mutex); if (triggerAddressAndValue.size() < 2) { diff --git a/src/launcher/CMakeLists.txt b/src/launcher/CMakeLists.txt index 41ffe9f..d5fdb58 100644 --- a/src/launcher/CMakeLists.txt +++ b/src/launcher/CMakeLists.txt @@ -58,8 +58,8 @@ FILE(GLOB_RECURSE APP_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") FILE(GLOB_RECURSE APP_UI_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.ui") INCLUDE_DIRECTORIES(${CMAEK_CURRENT_BINARY_DIR}) -set(RESOURCES_DIR ${CMAKE_SOURCE_DIR}"/resources/resources.qrc") -set(WIN_RC_DIR ${CMAKE_SOURCE_DIR}"/resources/ff.rc") +set(RESOURCES_DIR ${CMAKE_SOURCE_DIR}/resources/resources.qrc) +set(WIN_RC_DIR ${CMAKE_SOURCE_DIR}/resources/ff.rc) include_directories(${CMAKE_BINARY_DIR}) add_executable( ${CURRENT_FOLDER} ${APP_HEADERPP_FILES} diff --git a/src/launcher/GUI/JsonEditorDialog.h b/src/launcher/GUI/JsonEditorDialog.h index a270e8c..e2a6121 100644 --- a/src/launcher/GUI/JsonEditorDialog.h +++ b/src/launcher/GUI/JsonEditorDialog.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -17,6 +17,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include + class JsonParamTableEditor : public QDialog { Q_OBJECT @@ -35,12 +42,48 @@ public: : QDialog(parent) { this->setWindowTitle("JSON 表格编辑器"); this->resize(700, 450); - setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint); // 去掉边框 //现在、、 + setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);// 去掉边框 //setAttribute(Qt::WA_TranslucentBackground); // 背景透明 this->setObjectName("JsonParamTableEditor"); this->setStyleSheet(QString("QDialog#JsonParamTableEditor {background-color: rgb(%1);border: 2px solid #000000;border-radius: 6px;}").arg(sColor_Blue)); - m_tableWidget = new QTableWidget(0, 2, this); - m_tableWidget->setHorizontalHeaderLabels({ "选项", "值" }); + + m_tableView = new QTableView(this); + m_tableModel = new QStandardItemModel(0, 2, this);// 2列:选项、值 + m_tableView->setModel(m_tableModel); + m_tableView->setCornerButtonEnabled(false); + + // 设置无边框 + m_tableView->setFrameShape(QFrame::NoFrame); + m_tableView->setShowGrid(false); + + // 禁止拖动单元格大小 + m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); + m_tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + + // 禁止点击表头 + m_tableView->horizontalHeader()->setSectionsClickable(false); + m_tableView->verticalHeader()->setSectionsClickable(false); + + // 禁止点击第一列的单元格 + m_tableView->setEditTriggers(QAbstractItemView::EditTrigger::DoubleClicked | QAbstractItemView::EditTrigger::EditKeyPressed); + m_tableView->setItemDelegateForColumn(0, new QStyledItemDelegate(m_tableView)); + m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_tableView->setSelectionMode(QAbstractItemView::SingleSelection); + m_tableView->setColumnWidth(0, 120); // 可根据实际调整 + + // 禁止第一列选中 + m_tableView->setColumnHidden(0, false); // 显示第一列 + m_tableView->setFocusPolicy(Qt::NoFocus); + + //设置表头 + m_tableModel->setHorizontalHeaderLabels({ "选项", "值" }); + + //设置表格属性 + m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_tableView->setAlternatingRowColors(true); + m_tableView->horizontalHeader()->setStretchLastSection(true); + m_tableView->setColumnWidth(1, 200);// 选项列宽度 + fancyButtonText* okBtn = new fancyButtonText("保存", 70, 22, ""); fancyButtonText* cancelBtn = new fancyButtonText("取消", 70, 22, ""); @@ -54,65 +97,119 @@ public: btnLayout->addWidget(cancelBtn); QVBoxLayout* mainLayout = new QVBoxLayout(this); - mainLayout->addWidget(m_tableWidget); + mainLayout->addWidget(m_tableView); 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"; - color: #ffffff; - gridline-color: #555555; - } - QHeaderView::section { - background-color: #0078d7; - padding: 4px; - font-weight: bold; - color: #ffffff; - } - QTableWidget::item:selected { - background-color: #0078d7; - } - )").arg(sColor_Blue)); + m_tableView->setStyleSheet(QString(R"( + QTableView { + background-color: rgb(%1); + font-family: "Microsoft YaHei"; + color: #ffffff; + gridline-color: #555555; + alternate-background-color: #3a3a3a; + } + QTableView::item { + background-color: transparent; + } + QTableView::item:selected { + background-color: transparent; + } + QTableView::item:alternate { + background-color: transparent; + } + QTableCornerButton::section { + background: transparent; +border: none; + } + )").arg(sColor_Blue)); + + QString headerStyle = QStringLiteral( + "QHeaderView {" + "background-color: transparent;" + "border: none;" + "}" + "QHeaderView::section {" + "background-color: transparent;" + "font-family: 'Microsoft YaHei';" + "font-weight: bold;" + "color: #ffffff;" + "border: none;" + "padding: 4px;" + "}" + ); + m_tableView->horizontalHeader()->setStyleSheet(headerStyle); + m_tableView->verticalHeader()->setStyleSheet(( + headerStyle + + "QHeaderView {" + "background-color: rgb(%1);" + "}" + ).arg(sColor_Blue));; + m_tableView->setCornerButtonEnabled(false); + + // 强制隐藏交叉方块区域 + m_tableView->horizontalHeader()->setFixedHeight( + m_tableView->horizontalHeader()->height() - 1); + m_tableView->verticalHeader()->setFixedWidth( + m_tableView->verticalHeader()->width() - 1); + } void setJsonObject(const nlohmann::json& json) { - m_tableWidget->setRowCount(0); + m_tableModel->setRowCount(0); m_originalJson = json; // 保存原始JSON m_originalTypes.clear(); // 清空原始类型映射 + m_editorWidgets.clear(); if (!json.is_object()) return; + int row = 0; for (auto it = json.begin(); it != json.end(); ++it) { - int row = m_tableWidget->rowCount(); - m_tableWidget->insertRow(row); + m_tableModel->insertRow(row); const std::string& key = it.key(); const nlohmann::json& value = it.value(); - + + //// 设置行号(不可编辑) + //QStandardItem* rowItem = new QStandardItem(QString::number(row + 1)); + //rowItem->setEditable(false); + //rowItem->setBackground(QColor(60, 60, 60)); + //rowItem->setForeground(QColor(255, 255, 255)); + //m_tableModel->setItem(row, 0, rowItem); + // 设置键名(不可编辑) - 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); + QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key)); + keyItem->setEditable(false); + keyItem->setBackground(QColor(60, 60, 60)); + keyItem->setForeground(QColor(255, 255, 255)); + m_tableModel->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); + ////为所有类型都创建数据项 + //QString valueText = formatValueForDisplay(value, valueType); + //QStandardItem* valueItem = new QStandardItem(valueText); + //valueItem->setToolTip(generateTypeHint(valueType)); + //valueItem->setBackground(QColor(60, 60, 60)); + //valueItem->setForeground(QColor(255, 255, 255)); + //m_tableModel->setItem(row, 1, valueItem); + + //为特定类型创建专用编辑器控件 + QWidget* editorWidget = createEditorWidget(value, valueType); + if (editorWidget) { + m_tableView->setIndexWidget(m_tableModel->index(row, 1), editorWidget); + m_editorWidgets[key] = editorWidget; + } + else { + // 默认为文本显示 + QString valueText= formatValueForDisplay(value, valueType); + QStandardItem* valueItem = new QStandardItem(valueText); + valueItem->setToolTip(generateTypeHint(valueType)); + m_tableModel->setItem(row, 1, valueItem); + } + row++; } - m_tableWidget->resizeColumnsToContents(); } signals: @@ -122,24 +219,20 @@ private slots: void onAccept() { nlohmann::json result = nlohmann::json::object(); - for (int row = 0; row < m_tableWidget->rowCount(); ++row) { - auto* keyItem = m_tableWidget->item(row, 0); - auto* valItem = m_tableWidget->item(row, 1); - - if (!keyItem || !valItem) { + for (int row = 0; row < m_tableModel->rowCount(); ++row) { + QStandardItem* keyItem = m_tableModel->item(row, 0); + if (!keyItem) { QMessageBox::warning(this, "错误", QString("第 %1 行数据不完整").arg(row + 1)); return; } QString key = keyItem->text().trimmed(); - QString valStr = valItem->text().trimmed(); - if (key.isEmpty()) { QMessageBox::warning(this, "错误", QString("第 %1 行 key 为空").arg(row + 1)); return; } - // 获取原始类型 + //获取原始类型 std::string keyStd = key.toStdString(); if (m_originalTypes.find(keyStd) == m_originalTypes.end()) { QMessageBox::warning(this, "错误", QString("第 %1 行找不到原始类型信息").arg(row + 1)); @@ -148,26 +241,160 @@ private slots: 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)); + if (!getValueFromEditor(keyStd, expectedType, convertedValue, errorMsg)) { + QMessageBox::critical(this, "类型验证失败",QString("第 %1 行值验证失败:\n%2").arg(row + 1).arg(errorMsg)); return; } - result[keyStd] = convertedValue; } + qDebug() << "Result JSON: " << QString::fromStdString(result.dump(4)); + emit jsonAccepted(result); accept(); } private: - QTableWidget* m_tableWidget; + QTableView* m_tableView; + QStandardItemModel* m_tableModel; nlohmann::json m_originalJson; // 保存原始JSON以便类型检查 - std::map m_originalTypes; // 保存每个键的原始类型 + std::map m_originalTypes;// 保存每个键的原始类型 + std::map m_editorWidgets;// 保存每个键对应的编辑器控件 + + // 根据类型创建不同的编辑器控件 + QWidget* createEditorWidget(const nlohmann::json& value, JsonValueType type) { + switch (type) { + case JsonValueType::Boolean: { + CircularSwitch* switchBtn = new CircularSwitch(); + switchBtn->setChecked(value.get()); + switchBtn->setToolTip(generateTypeHint(type)); + return switchBtn; + } + case JsonValueType::Number: { + QDoubleSpinBox* spinBox = new QDoubleSpinBox(); + spinBox->setRange(-1e18, 1e18); + spinBox->setDecimals(3);//显示小位数 + + if (value.is_number_integer()) { + spinBox->setValue(value.get()); + spinBox->setDecimals(0); + } + else { + spinBox->setValue(value.get()); + } + + spinBox->setToolTip(generateTypeHint(type)); + return spinBox; + } + case JsonValueType::String: { + QLineEdit* lineEdit = new QLineEdit(); + lineEdit->setText(QString::fromStdString(value.get())); + lineEdit->setToolTip(generateTypeHint(type)); + return lineEdit; + } + // 其他类型仍使用文本显示 + default: + return nullptr; + } + } + + bool getValueFromEditor(const std::string& key, JsonValueType expectedType, nlohmann::json& result, QString& errorMsg) { + auto it = m_editorWidgets.find(key); + + try { + if (it != m_editorWidgets.end()) { + // 有专用编辑器控件 + QWidget* widget = it->second; + switch (expectedType) { + case JsonValueType::Boolean: { + CircularSwitch* switchBtn = qobject_cast(widget); + if (switchBtn) { + bool value = switchBtn->isChecked(); + result = value; + // 更新模型数据 + updateModelData(key, value ? "true" : "false"); + return true; + } + errorMsg = "布尔值控件类型错误"; + return false; + } + case JsonValueType::Number: { + QDoubleSpinBox* spinBox = qobject_cast(widget); + if (spinBox) { + double value = spinBox->value(); + // 检查是否为整数 + if (spinBox->decimals() == 0 && value == floor(value)) { + result = static_cast(value); + updateModelData(key, QString::number(static_cast(value))); + } + else { + result = value; + updateModelData(key, QString::number(value)); + } + return true; + } + errorMsg = "数字控件类型错误"; + return false; + } + case JsonValueType::String: { + QLineEdit* lineEdit = qobject_cast(widget); + if (lineEdit) { + QString value = lineEdit->text().trimmed(); + result = value.toStdString(); + updateModelData(key, value); + return true; + } + errorMsg = "字符串控件类型错误"; + return false; + } + default: + // 其他类型使用默认文本处理 + return validateAndConvertValue(getTextFromCell(key), expectedType, result, errorMsg); + } + } + else { + // 没有专用编辑器控件,使用默认文本处理 + return validateAndConvertValue(getTextFromCell(key), expectedType, result, errorMsg); + } + } + catch (const std::exception& e) { + errorMsg = QString("获取值错误: %1").arg(e.what()); + return false; + } + } + + // 更新模型中的数据项 + void updateModelData(const std::string& key, const QString& value) { + for (int row = 0; row < m_tableModel->rowCount(); ++row) { + QStandardItem* keyItem = m_tableModel->item(row, 0); + if (keyItem && keyItem->text().toStdString() == key) { + QStandardItem* valueItem = m_tableModel->item(row, 1); + if (valueItem) { + valueItem->setText(value); + } + break; + } + } + } + + // 从单元格获取文本值(用于没有专用编辑器的类型) + QString getTextFromCell(const std::string& key) { + //查找键对应的行 + for (int row = 0; row < m_tableModel->rowCount(); ++row) { + QStandardItem* keyItem = m_tableModel->item(row, 0); + if (keyItem && keyItem->text().toStdString() == key) { + QStandardItem* valueItem = m_tableModel->item(row, 1); + if (valueItem) { + return valueItem->text(); + } + break; + } + } + return ""; + } // 获取JSON值的类型 JsonValueType getJsonValueType(const nlohmann::json& value) { diff --git a/src/launcher/GUI/uiModule/components/sliderSwitch.h b/src/launcher/GUI/uiModule/components/sliderSwitch.h new file mode 100644 index 0000000..0b1378d --- /dev/null +++ b/src/launcher/GUI/uiModule/components/sliderSwitch.h @@ -0,0 +1,287 @@ +#ifndef CIRCULARSWITCH_H +#define CIRCULARSWITCH_H + +#include +#include +#include +#include +#include +#include + +class CircularSwitch : public QWidget +{ + Q_OBJECT + Q_PROPERTY(int knobPosition READ knobPosition WRITE setKnobPosition NOTIFY knobPositionChanged) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged) + +public: + explicit CircularSwitch(QWidget* parent = nullptr) + : QWidget(parent) + , m_checked(false) + , m_knobPosition(0) + , m_animationDuration(200) + , m_onColor(QColor("#4CD964")) + , m_offColor(QColor("#E5E5EA")) + , m_knobColor(Qt::white) + , m_borderColor(QColor("#CCCCCC")) + , m_textColor(Qt::white) + , m_knobDiameter(0) + , m_padding(3) + , m_borderWidth(1) + , m_showText(true) + , m_trueText("true") + , m_falseText("false") + { + m_animation = new QPropertyAnimation(this, "knobPosition", this); + m_animation->setEasingCurve(QEasingCurve::OutCubic); + m_animation->setDuration(m_animationDuration); + + setFixedSize(70, 34); // 稍微加宽以容纳文字 + setCursor(Qt::PointingHandCursor); + updateKnobGeometry(); + } + + // 获取和设置开关状态 + bool isChecked() const { return m_checked; } + + void setChecked(bool checked) { + if (m_checked == checked) return; + + m_checked = checked; + update(); + + // 启动动画 + m_animation->stop(); + m_animation->setStartValue(m_knobPosition); + m_animation->setEndValue(checked ? width() - m_knobDiameter - m_padding : m_padding); + m_animation->start(); + + // 延迟发射信号,让动画先执行 + QTimer::singleShot(10, this, [this, checked]() { + emit toggled(checked); + }); + } + + // 颜色设置 + QColor onColor() const { return m_onColor; } + void setOnColor(const QColor& color) { + m_onColor = color; + update(); + } + + QColor offColor() const { return m_offColor; } + void setOffColor(const QColor& color) { + m_offColor = color; + update(); + } + + QColor knobColor() const { return m_knobColor; } + void setKnobColor(const QColor& color) { + m_knobColor = color; + update(); + } + + QColor borderColor() const { return m_borderColor; } + void setBorderColor(const QColor& color) { + m_borderColor = color; + update(); + } + + QColor textColor() const { return m_textColor; } + void setTextColor(const QColor& color) { + m_textColor = color; + update(); + } + + QColor backgroundColor() const { + return m_checked ? m_onColor : m_offColor; + } + + void setBackgroundColor(const QColor& color) { + if (m_checked) { + m_onColor = color; + } + else { + m_offColor = color; + } + update(); + } + + // 动画设置 + int animationDuration() const { return m_animationDuration; } + void setAnimationDuration(int duration) { + m_animationDuration = duration; + m_animation->setDuration(duration); + } + + // 边框设置 + int borderWidth() const { return m_borderWidth; } + void setBorderWidth(int width) { + m_borderWidth = width; + update(); + } + + // 文字设置 + bool showText() const { return m_showText; } + void setShowText(bool show) { + m_showText = show; + update(); + } + + QString trueText() const { return m_trueText; } + void setTrueText(const QString& text) { + m_trueText = text; + update(); + } + + QString falseText() const { return m_falseText; } + void setFalseText(const QString& text) { + m_falseText = text; + update(); + } + +protected: + void paintEvent(QPaintEvent* event) override { + Q_UNUSED(event) + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + // 绘制背景 + QRect backgroundRect = rect().adjusted(m_padding, m_padding, -m_padding, -m_padding); + QPainterPath backgroundPath; + backgroundPath.addRoundedRect(backgroundRect, backgroundRect.height() / 2, backgroundRect.height() / 2); + + // 绘制边框 + if (m_borderWidth > 0) { + painter.setPen(QPen(m_borderColor, m_borderWidth)); + painter.setBrush(Qt::NoBrush); + painter.drawPath(backgroundPath); + } + + // 绘制填充背景 + painter.setPen(Qt::NoPen); + painter.setBrush(m_checked ? m_onColor : m_offColor); + painter.drawPath(backgroundPath); + + // 绘制背景文字 + if (m_showText) { + painter.setPen(m_textColor); + QFont font = painter.font(); + font.setPointSize(8); + font.setBold(true); + painter.setFont(font); + + // 计算文字位置 + QRect textRect = backgroundRect; + + if (m_checked) { + // 打开状态,文字在左侧 + textRect.setRight(width() / 2); + painter.drawText(textRect, Qt::AlignCenter, m_trueText); + } + else { + // 关闭状态,文字在右侧 + textRect.setLeft(width() / 2); + painter.drawText(textRect, Qt::AlignCenter, m_falseText); + } + } + + // 绘制滑块 + int knobY = height() / 2; + QRect knobRect(m_knobPosition, knobY - m_knobDiameter / 2, + m_knobDiameter, m_knobDiameter); + + QPainterPath knobPath; + knobPath.addEllipse(knobRect); + + // 滑块阴影效果 + QRadialGradient gradient(knobRect.center(), m_knobDiameter / 2); + gradient.setColorAt(0, m_knobColor.lighter(110)); + gradient.setColorAt(1, m_knobColor); + + painter.setPen(QPen(m_borderColor, 1)); + painter.setBrush(gradient); + painter.drawPath(knobPath); + + // 滑块内阴影效果 + if (m_checked) { + QRect innerKnobRect = knobRect.adjusted(3, 3, -3, -3); + QPainterPath innerKnobPath; + innerKnobPath.addEllipse(innerKnobRect); + + QRadialGradient innerGradient(innerKnobRect.center(), innerKnobRect.width() / 2); + innerGradient.setColorAt(0, QColor(255, 255, 255, 100)); + innerGradient.setColorAt(1, QColor(255, 255, 255, 0)); + + painter.setPen(Qt::NoPen); + painter.setBrush(innerGradient); + painter.drawPath(innerKnobPath); + } + } + + void mousePressEvent(QMouseEvent* event) override { + if (event->button() == Qt::LeftButton) { + event->accept(); + setChecked(!m_checked); + } + else { + event->ignore(); + } + } + + void resizeEvent(QResizeEvent* event) override { + Q_UNUSED(event) + updateKnobGeometry(); + // 更新滑块位置 + setKnobPosition(m_checked ? width() - m_knobDiameter - m_padding : m_padding); + } + +private: + int knobPosition() const { return m_knobPosition; } + + void setKnobPosition(int position) { + if (m_knobPosition != position) { + m_knobPosition = position; + update(); + emit knobPositionChanged(position); + } + } + + void updateKnobGeometry() { + m_knobDiameter = height() - 2 * m_padding - 2 * m_borderWidth; + // 确保滑块是圆形 + if (m_knobDiameter > width() / 2 - m_padding) { + m_knobDiameter = width() / 2 - m_padding; + } + } + +private: + bool m_checked; + int m_knobPosition; + int m_animationDuration; + + QColor m_onColor; + QColor m_offColor; + QColor m_knobColor; + QColor m_borderColor; + QColor m_textColor; + + QPropertyAnimation* m_animation; + + int m_knobDiameter; + int m_padding; + int m_borderWidth; + + // 文字相关属性 + bool m_showText; + QString m_trueText; + QString m_falseText; + +signals: + void toggled(bool checked); + void knobPositionChanged(int position); + void backgroundColorChanged(const QColor& color); +}; + +#endif // CIRCULARSWITCH_H \ No newline at end of file diff --git a/src/launcher/GUI/uiModule/uiModule_runCommand.h b/src/launcher/GUI/uiModule/uiModule_runCommand.h index 41c0ea8..0184918 100644 --- a/src/launcher/GUI/uiModule/uiModule_runCommand.h +++ b/src/launcher/GUI/uiModule/uiModule_runCommand.h @@ -55,18 +55,31 @@ public: this->setWindowTitle("执行命令"); this->setObjectName("runCommandWidget"); this->setStyleSheet(QString("QDialog#runCommandWidget {background-color: rgb(%1);border: 2px solid #000000;border-radius: 6px;}").arg(sColor_Blue)); - + this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); + btnWidgets = new QListWidget(this); btnWidgets->setStyleSheet("background: transparent;"); - plcValueViewerLayout = new QVBoxLayout(); - //plcValueViewerLayout->setStyleSheet("background: transparent;"); + QWidget* listContainer = new QWidget(this); + plcValueViewerLayout = new QVBoxLayout(listContainer); + plcValueViewerLayout->setContentsMargins(0, 0, 0, 0); + plcValueViewerLayout->setSpacing(6); + listContainer->setLayout(plcValueViewerLayout); + listContainer->setStyleSheet("background: transparent;"); + + QScrollArea* scrollArea = new QScrollArea(this); + scrollArea->setWidgetResizable(true); + scrollArea->setFrameShape(QFrame::NoFrame); + scrollArea->setWidget(listContainer); + scrollArea->setStyleSheet("background: transparent;"); QGridLayout* layout = new QGridLayout(this); layout->addWidget(btnWidgets, 0, 0); - layout->addLayout(plcValueViewerLayout, 0, 1); + layout->addWidget(scrollArea, 0, 1); this->setFixedWidth(sizeX); + this->setMinimumHeight(sizeY); + //this->setMaximumHeight(sizeY); } signals: @@ -101,7 +114,7 @@ public slots: } } private: - int sizeX = 1000, sizeY = 500; + int sizeX = 1000, sizeY = 800; QListWidget* btnWidgets; QVBoxLayout* plcValueViewerLayout; QMap>plcViwerLineedits; diff --git a/src/launcher/GUI/uiModule/uiModule_softwareDataDisplay.h b/src/launcher/GUI/uiModule/uiModule_softwareDataDisplay.h index 73a898a..311fe53 100644 --- a/src/launcher/GUI/uiModule/uiModule_softwareDataDisplay.h +++ b/src/launcher/GUI/uiModule/uiModule_softwareDataDisplay.h @@ -60,10 +60,15 @@ public: runStateText->setFont(font); runStateText->setPalette(palette); + triggerState =new QLabel(""); + triggerState->setFont(font); + triggerState->setPalette(palette); + runStateLayout->addWidget(runStateIconLabel); runStateLayout->addWidget(runStateText, 1, Qt::AlignCenter); mainLayout->addLayout(runStateLayout); + mainLayout->addWidget(triggerState, 1, Qt::AlignCenter); } layout->addLayout(mainLayout); @@ -72,7 +77,7 @@ public: "QLineEdit { background-color: #333; color: white; border-radius: 4px; padding: 2px; } " "QLabel { color: white; } " ); - //this->setFixedHeight(150); + this->setFixedWidth(200); } protected: @@ -105,16 +110,19 @@ private slots: runStateText->setToolTip(tooltip); } - void onMonitorError(const QString& error) { runStateText->setText("监控异常"); runStateText->setStyleSheet("QLabel { color: #999; }"); runStateText->setToolTip(QString("监控错误: %1").arg(error)); } - +public slots: + void onTriggerSateChanged(int loopCounterPerMin, int maxInterval) { + int activeThreadCount = QThreadPool::globalInstance()->activeThreadCount(); + triggerState->setText(QString::number(loopCounterPerMin) + "L " + QString::number(maxInterval) + "ms " + QString::number(activeThreadCount) + "T"); + } private: QTimer* timer; - QLabel* softwareRunTimeValue,* runStateText; + QLabel* softwareRunTimeValue,* runStateText,* triggerState; QElapsedTimer startTimer; }; diff --git a/src/launcher/appConfig/appConfig.cpp b/src/launcher/appConfig/appConfig.cpp index 12136d0..6ccfe95 100644 --- a/src/launcher/appConfig/appConfig.cpp +++ b/src/launcher/appConfig/appConfig.cpp @@ -31,5 +31,16 @@ void appConfig::parsingSettingJson() } missionJsonPath = appWorkPath.string() + "/config/" + objectSelect + ".json"; - //if(missionJson["backend"]["missionSettings"].at) + if (missionJson["backend"]["missionSettings"].contains("存储原图") == false) { + missionJson["backend"]["missionSettings"]["存储原图"] = true; + } + if (missionJson["backend"]["missionSettings"].contains("存储结果图") == false) { + missionJson["backend"]["missionSettings"]["存储结果图"] = true; + } + if (missionJson["backend"]["missionSettings"].contains("存储Seg图") == false) { + missionJson["backend"]["missionSettings"]["存储Seg图"] = true; + } + if (missionJson["backend"]["missionSettings"].contains("存储Cls图") == false) { + missionJson["backend"]["missionSettings"]["存储Cls图"] = true; + } } diff --git a/src/launcher/main.cpp b/src/launcher/main.cpp index 22f457e..39d2b65 100644 --- a/src/launcher/main.cpp +++ b/src/launcher/main.cpp @@ -164,6 +164,10 @@ void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge* _MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::addPlcValueViewer); QObject::connect(bridge, &qtFuncBridge::runCommand_refeshPlcValueViewer, _MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::refreshPlcValueViewer); + + //性能监测 + QObject::connect(bridge, &qtFuncBridge::sendTriggerManagerLoopData, + _MainWindow->_displayWidget->_softwareDataDisplay, &softwareDataDisplay::onTriggerSateChanged); } int main(int argc, char* argv[]) diff --git a/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h index e96f91d..990740a 100644 --- a/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h +++ b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h @@ -13,7 +13,20 @@ public: # include "HalconCpp.h" using namespace HDevEngineCpp; using namespace HalconCpp; - +void exceptionResume(std::shared_ptr data, mfd_detParams* _detParams, yh_581_address address, QString why = "") { + qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode) << why; + cv::Mat Paint; + data->oriImgs[0].copyTo(Paint); + if (Paint.channels() == 1) + cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); + TextRendererZH textPainter(Paint.cols, Paint.rows, 15); + textPainter.putText(Paint, "NG", cv::Point(1000, 50), cv::Scalar(0, 255, 0)); + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + data->resultImgs.push_back(Paint); + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.01");//结果反馈 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.01");//结果反馈 +} static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh_581_address address){ HObject ho_in_image; @@ -202,130 +215,134 @@ static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh 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; - } + try { + 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); - //处理算法 + 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"); + 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){ + 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");//发送结果 - qDebug() << __FUNCTION__ << " line:" << __LINE__ << " 预焊X偏移abs(resultData[0]) >= 6000,may err,set 0"; - data->halconOK = false; + 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 { - 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; + textPainter.putText(Paint, "NG", cv::Point(50, 500), cv::Scalar(0, 0, 255)); + sqlMapData["结果"] = "NG"; } - //圆及十字 - 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); + data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), sqlMapData); + data->resultImgs.push_back(Paint); - 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)); + return true; } - 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; + CATCH_EXCEPTIONS + exceptionResume(data, _detParams, address, "NG"); } diff --git a/updateLog/2025-10-17/屏幕截图 2025-10-17 095806.png b/updateLog/2025-10-17/屏幕截图 2025-10-17 095806.png new file mode 100644 index 0000000..dee20f4 Binary files /dev/null and b/updateLog/2025-10-17/屏幕截图 2025-10-17 095806.png differ diff --git a/updateLog/2025-10-17/屏幕截图 2025-10-17 095811.png b/updateLog/2025-10-17/屏幕截图 2025-10-17 095811.png new file mode 100644 index 0000000..34d75cb Binary files /dev/null and b/updateLog/2025-10-17/屏幕截图 2025-10-17 095811.png differ