diff --git a/diagramCavas/CMakeLists.txt b/diagramCavas/CMakeLists.txt index f0ff13f..28ea2ff 100644 --- a/diagramCavas/CMakeLists.txt +++ b/diagramCavas/CMakeLists.txt @@ -53,6 +53,7 @@ set(DIAGRAMCAVAS_HEADER_FILES include/dataSourceDlg.h include/createHMIdlg.h include/propertyDialog.h + include/eventPropertyEditor.h include/graphicsDataModel/baseModel.h include/graphicsDataModel/fixedPortsModel.h include/graphicsItem/graphicsItemGroup.h @@ -91,6 +92,7 @@ set(DIAGRAMCAVAS_HEADER_FILES include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h include/graphicsItem/functionModelItem/electricFunctionModelSvgItemImage.h include/graphicsItem/functionModelItem/electricFunctionModelItemText.h + include/graphicsItem/functionModelItem/graphicsEventContext.h include/baseModelItem/electricBaseModelSvgItem.h include/baseModelItem/electricBaseModelLineItem.h @@ -113,7 +115,16 @@ set(DIAGRAMCAVAS_HEADER_FILES include/propertyType/dataSourceType.h include/propertyType/PropertyTypeCustomization_CustomType.h include/propertyType/propertyTypeCustomization_DataSourceType.h + include/propertyType/propertyTypeCustomization_ConfigEventData.h include/propertyType/pannelColorGadget.h + include/propertyType/configEventData.h + + include/evetConfig/eventExecutor.h + include/evetConfig/eventHandler.h + include/evetConfig/panelVisibilityEventHandler.h + include/evetConfig/scriptEventHandler.h + include/evetConfig/variableSetEventHandler.h + ../common/include/httpInterface.h ../common/include/tools.h ../common/include/baseProperty.h @@ -242,6 +253,7 @@ set(DIAGRAMCAVAS_SOURCE_FILES source/propertyType/PropertyTypeCustomization_CustomType.cpp source/propertyType/propertyTypeCustomization_DataSourceType.cpp + source/propertyType/propertyTypeCustomization_ConfigEventData.cpp source/propertyType/pannelColorGadget.cpp ../common/source/httpInterface.cpp ../common/source/baseProperty.cpp diff --git a/diagramCavas/include/configEvent.h b/diagramCavas/include/configEvent.h new file mode 100644 index 0000000..ec1cb53 --- /dev/null +++ b/diagramCavas/include/configEvent.h @@ -0,0 +1,132 @@ +#pragma once + +/*************************HMI事件组态**************************/ +#include +#include +#include + +// 事件触发器类型 +enum class TriggerType { + Click = 0, + DoubleClick, + RightClick, + HoverEnter, + HoverLeave, + PropertyChange, + Unknown +}; + +QString triggerTypeToString(TriggerType type) { + switch (type) { + case TriggerType::Click: return "click"; + case TriggerType::DoubleClick: return "double_click"; + case TriggerType::RightClick: return "right_click"; + case TriggerType::HoverEnter: return "hover_enter"; + case TriggerType::HoverLeave: return "hover_leave"; + case TriggerType::PropertyChange: return "property_change"; + default: return "unknown"; + } +} + +TriggerType stringToTriggerType(const QString& str) { + QMap mapping = { + {"click", TriggerType::Click}, + {"double_click", TriggerType::DoubleClick}, + {"right_click", TriggerType::RightClick}, + {"hover_enter", TriggerType::HoverEnter}, + {"hover_leave", TriggerType::HoverLeave}, + {"property_change", TriggerType::PropertyChange} + }; + return mapping.value(str, TriggerType::Unknown); +} + +// 事件接口 +class IConfigEvent { +public: + virtual ~IConfigEvent() = default; + virtual void execute() = 0; + virtual QString type() const = 0; + virtual QJsonObject toJson() const = 0; + virtual void fromJson(const QJsonObject& json) = 0; + virtual IConfigEvent* clone() const = 0; +}; + +// Panel可见性事件 +class PanelVisibilityEvent : public IConfigEvent { + QString panelId; + bool visible = true; + +public: + void setPanelId(const QString& id) { panelId = id; } + void setVisible(bool v) { visible = v; } + + QString type() const override { return "panel_visibility"; } + + void execute() override { + // 实现Panel控制逻辑 + emit requestPanelControl(panelId, visible); + } + + QJsonObject toJson() const override { + return { + {"type", type()}, + {"panelId", panelId}, + {"visible", visible} + }; + } + + void fromJson(const QJsonObject& json) override { + panelId = json["panelId"].toString(); + visible = json["visible"].toBool(); + } + + IConfigEvent* clone() const override { + auto event = new PanelVisibilityEvent(); + event->panelId = panelId; + event->visible = visible; + return event; + } + +signals: + void requestPanelControl(const QString& panelId, bool visible); +}; + +// 变量赋值事件 +class VariableAssignmentEvent : public IConfigEvent { + QString varName; + QVariant value; + +public: + void setVariableName(const QString& name) { varName = name; } + void setValue(const QVariant& val) { value = val; } + + QString type() const override { return "variable_assignment"; } + + void execute() override { + // 变量赋值逻辑 + emit requestVariableAssignment(varName, value); + } + + QJsonObject toJson() const override { + return { + {"type", type()}, + {"variable", varName}, + {"value", value.toString()} + }; + } + + void fromJson(const QJsonObject& json) override { + varName = json["variable"].toString(); + value = json["value"].toString(); + } + + IConfigEvent* clone() const override { + auto event = new VariableAssignmentEvent(); + event->varName = varName; + event->value = value; + return event; + } + +signals: + void requestVariableAssignment(const QString& name, const QVariant& value); +}; diff --git a/diagramCavas/include/diagramCavas.h b/diagramCavas/include/diagramCavas.h index c0adea8..568644d 100644 --- a/diagramCavas/include/diagramCavas.h +++ b/diagramCavas/include/diagramCavas.h @@ -55,6 +55,8 @@ public: int getCurMode(){return _curMode;} void showPropertyDlg(); //加载运行时属性栏 void hidePropertyDlg(); + + void setHMIVisiblebyName(const QString& str,bool val); //通过名称打开对应HMI signals: void prepareUpdateItems(QList,bool refresh); void prepareSelectItems(QList); diff --git a/diagramCavas/include/eventPropertyEditor.h b/diagramCavas/include/eventPropertyEditor.h new file mode 100644 index 0000000..29748d5 --- /dev/null +++ b/diagramCavas/include/eventPropertyEditor.h @@ -0,0 +1,256 @@ +// eventpropertyeditor.h +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "propertyType/configEventData.h" + +class EventPropertyEditor : public QDialog { + Q_OBJECT + +public: + EventPropertyEditor(const EventList& initialEvents, QWidget* parent = nullptr) + : QDialog(parent), m_events(initialEvents) { + setupUI(); + loadEvents(); + } + + EventList getEvents() const { return m_events; } + +private slots: + void onAddEvent() { + // 简化的事件添加对话框 + QDialog dialog(this); + dialog.setWindowTitle("添加事件"); + QVBoxLayout* mainLayout = new QVBoxLayout(&dialog); + + QGridLayout* gridLayout = new QGridLayout(); + mainLayout->addLayout(gridLayout); + + int row = 0; + + // 触发器选择 + QComboBox* triggerCombo = new QComboBox(); + triggerCombo->addItems({"click", "doubleClick", "rightClick", "hoverEnter", "hoverLeave"}); + gridLayout->addWidget(new QLabel("触发器:"), row, 0); + gridLayout->addWidget(triggerCombo, row, 1); + row++; + + // 事件类型选择 + QComboBox* typeCombo = new QComboBox(); + typeCombo->addItems({"showPanel", "setVariable", "runScript"}); + gridLayout->addWidget(new QLabel("事件类型:"), row, 0); + gridLayout->addWidget(typeCombo, row, 1); + row++; + + // 动态参数区域 + QStackedWidget* paramStack = new QStackedWidget(); + gridLayout->addWidget(paramStack, row, 0, 1, 2); + row++; + + // 创建不同类型的参数页面 + QWidget* showPanelPage = createShowPanelPage(); + QWidget* setVariablePage = createSetVariablePage(); + QWidget* runScriptPage = createRunScriptPage(); + + paramStack->addWidget(showPanelPage); + paramStack->setCurrentIndex(0); + paramStack->addWidget(setVariablePage); + paramStack->addWidget(runScriptPage); + + // 连接类型变化信号 + connect(typeCombo, QOverload::of(&QComboBox::currentIndexChanged), + paramStack, &QStackedWidget::setCurrentIndex); + + QDialogButtonBox* buttons = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + mainLayout->addWidget(buttons); + + connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + + if (dialog.exec() == QDialog::Accepted) { + EventData event; + event.trigger = triggerCombo->currentText(); + event.type = typeCombo->currentText(); + + // 根据事件类型获取参数 + if (event.type == "showPanel") { + QLineEdit* panelIdEdit = showPanelPage->findChild("panelIdEdit"); + QComboBox* showCombo = showPanelPage->findChild("showCombo"); + + event.parameters["panelId"] = panelIdEdit->text(); + event.parameters["show"] = showCombo->currentText().toLower() == "true"; + event.description = QString("显隐面板: %1").arg(panelIdEdit->text()); + + } else if (event.type == "setVariable") { + QLineEdit* varNameEdit = setVariablePage->findChild("varNameEdit"); + QLineEdit* varValueEdit = setVariablePage->findChild("varValueEdit"); + + event.parameters["variable"] = varNameEdit->text(); + event.parameters["value"] = varValueEdit->text(); + event.description = QString("设置变量: %1 = %2").arg(varNameEdit->text(), varValueEdit->text()); + + } else if (event.type == "runScript") { + QLineEdit* scriptPathEdit = runScriptPage->findChild("scriptPathEdit"); + QComboBox* scriptTypeCombo = runScriptPage->findChild("scriptTypeCombo"); + + event.parameters["script"] = scriptPathEdit->text(); + event.parameters["type"] = scriptTypeCombo->currentText(); + event.description = QString("执行脚本: %1").arg(scriptPathEdit->text()); + } + + m_events.addEvent(event); + updateEventList(); + } + } + + void onEditEvent() { + int row = m_eventList->currentRow(); + if (row < 0 || row >= m_events.events.size()) return; + + // 简化的编辑:删除后重新添加 + m_events.events.removeAt(row); + onAddEvent(); + } + + void onDeleteEvent() { + int row = m_eventList->currentRow(); + if (row >= 0 && row < m_events.events.size()) { + m_events.events.removeAt(row); + updateEventList(); + } + } + +private: + void setupUI() { + setWindowTitle("事件编辑器"); + resize(500, 400); + + QVBoxLayout* mainLayout = new QVBoxLayout(this); + + // 事件列表 + m_eventList = new QListWidget(); + mainLayout->addWidget(m_eventList); + + // 按钮 + QHBoxLayout* btnLayout = new QHBoxLayout(); + QPushButton* addBtn = new QPushButton("添加"); + QPushButton* editBtn = new QPushButton("编辑"); + QPushButton* deleteBtn = new QPushButton("删除"); + + btnLayout->addWidget(addBtn); + btnLayout->addWidget(editBtn); + btnLayout->addWidget(deleteBtn); + btnLayout->addStretch(); + + mainLayout->addLayout(btnLayout); + + // 对话框按钮 + QDialogButtonBox* dialogBtns = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + mainLayout->addWidget(dialogBtns); + + // 连接信号 + connect(addBtn, &QPushButton::clicked, this, &EventPropertyEditor::onAddEvent); + connect(editBtn, &QPushButton::clicked, this, &EventPropertyEditor::onEditEvent); + connect(deleteBtn, &QPushButton::clicked, this, &EventPropertyEditor::onDeleteEvent); + connect(dialogBtns, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(dialogBtns, &QDialogButtonBox::rejected, this, &QDialog::reject); + } + + void loadEvents() { + updateEventList(); + } + + void updateEventList() { + m_eventList->clear(); + for (const auto& event : m_events.events) { + QString text = QString("%1: %2") + .arg(event.trigger, event.description); + m_eventList->addItem(text); + } + } + + // 创建"showPanel"类型参数的页面 + QWidget* createShowPanelPage() { + QWidget* page = new QWidget(); + QFormLayout* layout = new QFormLayout(page); + + QLineEdit* panelIdEdit = new QLineEdit(); + panelIdEdit->setObjectName("panelIdEdit"); + panelIdEdit->setPlaceholderText("输入面板ID,如: panel1"); + + QComboBox* showCombo = new QComboBox(); + showCombo->setObjectName("showCombo"); + showCombo->addItems({"true", "false"}); + + layout->addRow("面板ID:", panelIdEdit); + layout->addRow("显示/隐藏:", showCombo); + + return page; + } + + // 创建"setVariable"类型参数的页面 + QWidget* createSetVariablePage() { + QWidget* page = new QWidget(); + QFormLayout* layout = new QFormLayout(page); + + QLineEdit* varNameEdit = new QLineEdit(); + varNameEdit->setObjectName("varNameEdit"); + varNameEdit->setPlaceholderText("输入变量名,如: isVisible"); + + QLineEdit* varValueEdit = new QLineEdit(); + varValueEdit->setObjectName("varValueEdit"); + varValueEdit->setPlaceholderText("输入变量值,如: true, false, 123"); + + layout->addRow("变量名:", varNameEdit); + layout->addRow("变量值:", varValueEdit); + + return page; + } + + // 创建"runScript"类型参数的页面 + QWidget* createRunScriptPage() { + QWidget* page = new QWidget(); + QFormLayout* layout = new QFormLayout(page); + + QLineEdit* scriptPathEdit = new QLineEdit(); + scriptPathEdit->setObjectName("scriptPathEdit"); + scriptPathEdit->setPlaceholderText("输入脚本路径,如: scripts/init.js"); + + QPushButton* browseBtn = new QPushButton("浏览..."); + QHBoxLayout* pathLayout = new QHBoxLayout(); + pathLayout->addWidget(scriptPathEdit); + pathLayout->addWidget(browseBtn); + + QComboBox* scriptTypeCombo = new QComboBox(); + scriptTypeCombo->setObjectName("scriptTypeCombo"); + scriptTypeCombo->addItems({"js", "py", "lua"}); + + layout->addRow("脚本路径:", pathLayout); + layout->addRow("脚本类型:", scriptTypeCombo); + + // 可选:连接浏览按钮 + connect(browseBtn, &QPushButton::clicked, this, [scriptPathEdit]() { + QString path = QFileDialog::getOpenFileName(nullptr, "选择脚本文件", + "", "脚本文件 (*.js *.py *.lua)"); + if (!path.isEmpty()) { + scriptPathEdit->setText(path); + } + }); + + return page; + } +private: + EventList m_events; + QListWidget* m_eventList = nullptr; +}; diff --git a/diagramCavas/include/evetConfig/eventExecutor.h b/diagramCavas/include/evetConfig/eventExecutor.h new file mode 100644 index 0000000..db175f9 --- /dev/null +++ b/diagramCavas/include/evetConfig/eventExecutor.h @@ -0,0 +1,55 @@ +#pragma once +/**************************** + * 事件处理器的基类 + * *************************/ +#include "eventHandler.h" +#include "propertyType/configEventData.h" +#include "graphicsItem/functionModelItem/graphicsFunctionModelItem.h" +#include "evetConfig/panelVisibilityEventHandler.h" +#include "evetConfig/scriptEventHandler.h" +#include "evetConfig/variableSetEventHandler.h" + +class EventExecutor { +private: + QVector> m_handlers; + +public: + EventExecutor() { + // 注册默认处理器 + registerDefaultHandlers(); + } + + // 注册处理器 + void registerHandler(QSharedPointer handler) { + m_handlers.append(handler); + } + + // 执行事件 + void execute(const EventData& event, GraphicsFunctionModelItem* item) { + for (const auto& handler : m_handlers) { + if (handler->canHandle(event.type)) { + handler->handle(event, item); + return; + } + } + + // 如果没有找到处理器,使用默认处理 + qWarning() << "No handler found for event type:" << event.type; + } + + // 获取支持的处理器名称 + QStringList supportedHandlers() const { + QStringList names; + for (const auto& handler : m_handlers) { + names.append(handler->handlerName()); + } + return names; + } + +private: + void registerDefaultHandlers() { + registerHandler(QSharedPointer(new PanelVisibilityEventHandler())); + registerHandler(QSharedPointer(new VariableSetEventHandler())); + registerHandler(QSharedPointer(new ScriptEventHandler())); + } +}; diff --git a/diagramCavas/include/evetConfig/eventHandler.h b/diagramCavas/include/evetConfig/eventHandler.h new file mode 100644 index 0000000..4ea1962 --- /dev/null +++ b/diagramCavas/include/evetConfig/eventHandler.h @@ -0,0 +1,15 @@ +#pragma once +/**************************** + * 事件处理器的基类 + * *************************/ +#include "propertyType/configEventData.h" +#include "graphicsItem/functionModelItem/graphicsFunctionModelItem.h" +#include "graphicsItem/functionModelItem/graphicsEventContext.h" + +class EventHandler { +public: + virtual ~EventHandler() = default; + virtual bool canHandle(const QString& eventType) const = 0; + virtual void handle(const EventData& event, GraphicsFunctionModelItem* item) = 0; + virtual QString handlerName() const = 0; +}; diff --git a/diagramCavas/include/evetConfig/panelVisibilityEventHandler.h b/diagramCavas/include/evetConfig/panelVisibilityEventHandler.h new file mode 100644 index 0000000..90cd12a --- /dev/null +++ b/diagramCavas/include/evetConfig/panelVisibilityEventHandler.h @@ -0,0 +1,26 @@ +#pragma once +/**************************** + * 界面显隐处理器 + * *************************/ +#include "eventHandler.h" + +class PanelVisibilityEventHandler : public EventHandler { +public: + bool canHandle(const QString& eventType) const override { + return eventType == "showPanel" || eventType == "hidePanel"; + } + + void handle(const EventData& event, GraphicsFunctionModelItem* item) override { + QString panelId = event.parameters.value("panelId").toString(); + bool show = event.type == "showPanel"; + if (event.parameters.contains("show")) { + show = event.parameters.value("show").toBool(); + } + + if (auto context = item->eventContext()) { + context->emitPanelVisibilityChanged(panelId, show); + } + } + + QString handlerName() const override { return "PanelVisibilityHandler"; } +}; diff --git a/diagramCavas/include/evetConfig/scriptEventHandler.h b/diagramCavas/include/evetConfig/scriptEventHandler.h new file mode 100644 index 0000000..2317980 --- /dev/null +++ b/diagramCavas/include/evetConfig/scriptEventHandler.h @@ -0,0 +1,22 @@ +#pragma once +/**************************** + * 脚本执行处理器 + * *************************/ +#include "eventHandler.h" + +class ScriptEventHandler : public EventHandler { +public: + bool canHandle(const QString& eventType) const override { + return eventType == "runScript"; + } + + void handle(const EventData& event, GraphicsFunctionModelItem* item) override { + QString script = event.parameters.value("script").toString(); + + if (auto context = item->eventContext()) { + context->emitScriptExecuted(script); + } + } + + QString handlerName() const override { return "ScriptHandler"; } +}; diff --git a/diagramCavas/include/evetConfig/variableSetEventHandler.h b/diagramCavas/include/evetConfig/variableSetEventHandler.h new file mode 100644 index 0000000..f7d18c3 --- /dev/null +++ b/diagramCavas/include/evetConfig/variableSetEventHandler.h @@ -0,0 +1,23 @@ +#pragma once +/**************************** + * 变量控制处理器 + * *************************/ +#include "eventHandler.h" + +class VariableSetEventHandler : public EventHandler { +public: + bool canHandle(const QString& eventType) const override { + return eventType == "setVariable"; + } + + void handle(const EventData& event, GraphicsFunctionModelItem* item) override { + QString varName = event.parameters.value("variable").toString(); + QVariant value = event.parameters.value("value"); + + if (auto context = item->eventContext()) { + context->emitVariableSet(varName, value); + } + } + + QString handlerName() const override { return "VariableSetHandler"; } +}; diff --git a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h index 0ccee61..30466e1 100644 --- a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h +++ b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h @@ -106,6 +106,8 @@ public: void generateMonitorConfig(MonitorPanel*); //生成监控配置参数结构 void setMonitorPara(QMap> map){m_monitorPara = map;} QMap>& getMonitorPara() {return m_monitorPara;} + void setMonitorParaRef(QMap map){m_monitorParaRef = map;} + QMap& getMonitorParaRef(){return m_monitorParaRef;} void setMonitorRelation(QList lst){m_lstMonitorRelation = lst;} QList getMonitorRelation() {return m_lstMonitorRelation;} @@ -167,6 +169,10 @@ public Q_SLOTS: void onSignal_openBayManager(); void onDataTimerOut(); void onSelectionChanged(); + + void onPanelVisibilityChanged(const QString& panelName, bool show); //组态event 面板显隐 + void onVariantSet(QString varName,QVariant val); //组态event 变量赋值 + void onScriptExec(QString script); //组态event 脚本执行 private: void addPortsToItem_json(PortState,QJsonArray,GraphicsBaseItem*); //将json格式的port添加到item void autoSetModelName(GraphicsBaseModelItem*); //如果此页的工程模已被设置,将projectName更新到item @@ -194,6 +200,7 @@ private: ProjectIconSetting* m_projectIconSettingDlg; BayManagerDlg* m_pBayManager; QMap> m_monitorPara; //监控参数 + QMap m_monitorParaRef; //监控参数的引用关系(文字item等) QMap>> m_monitorStateMap; //元件状态对照表 > QMap> m_monitorDisplaySetting; //元件设置 QList m_lstMonitorRelation; //监控item层级关系 diff --git a/diagramCavas/include/graphicsItem/functionModelItem/graphicsEventContext.h b/diagramCavas/include/graphicsItem/functionModelItem/graphicsEventContext.h new file mode 100644 index 0000000..e063d48 --- /dev/null +++ b/diagramCavas/include/graphicsItem/functionModelItem/graphicsEventContext.h @@ -0,0 +1,29 @@ +#ifndef GRAPHICSEVENTCONTEXT_H +#define GRAPHICSEVENTCONTEXT_H +/***********组态事件信号**********/ +#include + +// 具体的文实现 +class GraphicsEventContext : public QObject { + Q_OBJECT + +signals: + void panelVisibilityChanged(const QString& panelId, bool show); + void variableSet(const QString& varName, const QVariant& value); + void scriptExecuted(const QString& script); + +public: + void emitPanelVisibilityChanged(const QString& panelId, bool show) { + emit panelVisibilityChanged(panelId, show); + } + + void emitVariableSet(const QString& varName, const QVariant& value) { + emit variableSet(varName, value); + } + + void emitScriptExecuted(const QString& script) { + emit scriptExecuted(script); + } +}; + +#endif diff --git a/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h b/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h index b5c8397..661c61c 100644 --- a/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h +++ b/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h @@ -2,14 +2,18 @@ #define GRAPHICSFUNCTIONMODELITEM_H #include "graphicsItem/graphicsBaseItem.h" +#include "propertyType/configEventData.h" class BaseItemPropertyProxy; +class GraphicsEventContext; +class EventExecutor; class GraphicsFunctionModelItem : public GraphicsProjectModelItem //功能模item { Q_OBJECT public: Q_PROPERTY(QMap PropertyVisible READ getMap WRITE setMap) + Q_PROPERTY(EventList Events READ getEvents WRITE setEvents) public: GraphicsFunctionModelItem(QGraphicsItem *parent); virtual ~GraphicsFunctionModelItem(); @@ -19,10 +23,22 @@ public: void setPropertyProxy(BaseItemPropertyProxy* p) {_pPropertyProxy = p;} BaseItemPropertyProxy* getPropertyProxy() {return _pPropertyProxy;} + + EventList getEvents() const; + void setEvents(const EventList& events); + void triggerEvents(const QString& triggerType); + + QSharedPointer eventContext() const { + return m_eventContext; + } protected: virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + void executeEvent(const EventData& event); protected: BaseItemPropertyProxy* _pPropertyProxy; //属性页代理 + QVector m_events; //HMI组态的事件 + QSharedPointer m_eventContext; + QSharedPointer m_eventExecutor; }; diff --git a/diagramCavas/include/graphicsItem/graphicsBaseItem.h b/diagramCavas/include/graphicsItem/graphicsBaseItem.h index d1d9a6d..ccdb144 100644 --- a/diagramCavas/include/graphicsItem/graphicsBaseItem.h +++ b/diagramCavas/include/graphicsItem/graphicsBaseItem.h @@ -639,6 +639,7 @@ protected: virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; signals: void ifExist(QUuid id,const QString&,int type,GraphicsProjectModelItem*); + void monitorParaRefSetted(QUuid id,QString connectPara); //参数引用被设置 引用者id,查询参数 public slots: void onEditNameFinish(const QString&); protected: diff --git a/diagramCavas/include/monitorPanel.h b/diagramCavas/include/monitorPanel.h index 3ca5f47..188e326 100644 --- a/diagramCavas/include/monitorPanel.h +++ b/diagramCavas/include/monitorPanel.h @@ -44,6 +44,9 @@ public: //对para的序列化与反序列化 QJsonArray serializeParaToJsonArray(const QMap>& data) const; bool deserializeParaFromJsonArray(const QJsonArray& jsonArray,QMap>& result); + //对paraRef的序列化与反序列化 + QJsonArray serializeUuidStringMap(const QMap& data); + bool deserializeUuidStringMap(const QJsonArray& jsonArray, QMap& result); //对displaySetiing的序列化与反序列化 QJsonArray serializeDisplayToJsonArray(const QMap>& data) const; void deserializeDisplayFromJsonArray(const QJsonArray& jsonArray,QMap>& result); diff --git a/diagramCavas/include/propertyType/configEventData.h b/diagramCavas/include/propertyType/configEventData.h new file mode 100644 index 0000000..decc989 --- /dev/null +++ b/diagramCavas/include/propertyType/configEventData.h @@ -0,0 +1,95 @@ +#pragma once +#include +#include +#include +#include +#include +#include +/****************HMI事件编辑***************/ +// 单个事件定义 +struct EventData { + QString id; // 事件ID + QString trigger; // 触发器: click, doubleClick, rightClick, hoverEnter, hoverLeave + QString type; // 事件类型: showPanel, hidePanel, setVariable, runScript + QVariantMap parameters; // 事件参数 + QString description; // 事件描述 + + EventData() { + id = QUuid::createUuid().toString(QUuid::WithoutBraces); + } + + EventData(const QString& t, const QString& trig, const QVariantMap& params = {}) + : trigger(trig), type(t), parameters(params) { + id = QUuid::createUuid().toString(QUuid::WithoutBraces); + } + + QJsonObject toJson() const { + return { + {"id", id}, + {"trigger", trigger}, + {"type", type}, + {"parameters", QJsonObject::fromVariantMap(parameters)}, + {"description", description} + }; + } + + void fromJson(const QJsonObject& json) { + id = json["id"].toString(); + trigger = json["trigger"].toString(); + type = json["type"].toString(); + parameters = json["parameters"].toObject().toVariantMap(); + description = json["description"].toString(); + } +}; + +static QDebug operator<<(QDebug debug, const EventData& it) { + return debug << it.id <<":"< events; + + EventList() = default; + + EventList(const QVector& evts) : events(evts) {} + + QJsonArray toJson() const { + QJsonArray arr; + for (const auto& event : events) { + arr.append(event.toJson()); + } + return arr; + } + + void fromJson(const QJsonArray& json) { + events.clear(); + for (const auto& val : json) { + EventData event; + event.fromJson(val.toObject()); + events.append(event); + } + } + + // 添加事件 + void addEvent(const EventData& event) { + events.append(event); + } + + // 查找事件 + EventData* findEvent(const QString& eventId) { + for (auto& event : events) { + if (event.id == eventId) { + return &event; + } + } + return nullptr; + } +}; + +static QDebug operator<<(QDebug debug, const EventList& it) { + return debug << it.events.size() ; +} +Q_DECLARE_METATYPE(EventList) diff --git a/diagramCavas/include/propertyType/propertyTypeCustomization_ConfigEventData.h b/diagramCavas/include/propertyType/propertyTypeCustomization_ConfigEventData.h new file mode 100644 index 0000000..5a9e77a --- /dev/null +++ b/diagramCavas/include/propertyType/propertyTypeCustomization_ConfigEventData.h @@ -0,0 +1,16 @@ +#ifndef PROPERTYTYPECUSTOMIZATION_CONFIGEVENTDATA_H +#define PROPERTYTYPECUSTOMIZATION_CONFIGEVENTDATA_H + +#include "IPropertyTypeCustomization.h" + +class EventPropertyEditor; + +class PropertyTypeCustomization_ConfigEventData : public IPropertyTypeCustomization { +protected: + virtual void customizeHeaderRow(QPropertyHandle* inPropertyHandle, QQuickDetailsViewRowBuilder* inBuilder) override; + virtual void customizeChildren(QPropertyHandle* inPropertyHandle, QQuickDetailsViewLayoutBuilder* inBuilder) override; +private: + EventPropertyEditor* _pDlg = nullptr; +}; + +#endif // PROPERTYTYPECUSTOMIZATION_CONFIGEVENTDATA_H diff --git a/diagramCavas/include/topologyManager.h b/diagramCavas/include/topologyManager.h index 325c996..713b24d 100644 --- a/diagramCavas/include/topologyManager.h +++ b/diagramCavas/include/topologyManager.h @@ -48,6 +48,7 @@ public: //==========================组态图拓扑相关=================================== PowerEntity* createDiagram(const QString& id,const QString& name,ModelFunctionType tpe = ModelFunctionType::ProjectModel); //单独创建组态图 PowerEntity* findDiagram(const QString& id,ModelFunctionType tpe = ModelFunctionType::ProjectModel) const; + PowerEntity* findDiagramByName(const QString& name,ModelFunctionType tpe = ModelFunctionType::ProjectModel) const; bool deleteDiagram(const QString& id,ModelFunctionType tpe = ModelFunctionType::ProjectModel); public: diff --git a/diagramCavas/source/diagramCavas.cpp b/diagramCavas/source/diagramCavas.cpp index c02f622..c2fbd7c 100644 --- a/diagramCavas/source/diagramCavas.cpp +++ b/diagramCavas/source/diagramCavas.cpp @@ -30,6 +30,7 @@ #include "QQuickDetailsViewMananger.h" #include "propertyType/propertyTypeCustomization_DataSourceType.h" +#include "propertyType/PropertyTypeCustomization_ConfigEventData.h" #include "propertyType/dataSourceType.h" #include "basePannelPropertyProxy.h" @@ -158,6 +159,7 @@ void DiagramCavas::initial() _structDataPreviewDlg->loadData(); QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization(); + QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization(); _createHMIDlg = new CreateHMIdlg(this); connect(_createHMIDlg,&CreateHMIdlg::createHMI,this,&DiagramCavas::onSignal_createHMIClicked); @@ -223,6 +225,20 @@ void DiagramCavas::hidePropertyDlg() _pPropertyDlg->hide(); } +void DiagramCavas::setHMIVisiblebyName(const QString& str,bool val) +{ + PowerEntity* pEntity = TopologyManager::instance().findDiagramByName(str,ModelFunctionType::RuntimeModel); + if(pEntity) + { + if(val) //显示 + onSignal_loadMonitor(pEntity); + else{ + if(m_mapMonitorPanel.contains(str)) + m_mapMonitorPanel[str].first->hide(); + } + } +} + void DiagramCavas::onSignal_addDrawingPanel(PowerEntity* pItem,DiagramMode mode,QString parent) { if(mode == DM_run){ diff --git a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp index ac8a7ea..b81495f 100644 --- a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp +++ b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp @@ -54,6 +54,7 @@ #include "baseItemPropertyProxy.h" #include "common/core_model/types.h" #include "graphicsItem/pluginSvgItemWrapper.h" +#include "graphicsItem/functionModelItem/graphicsEventContext.h" bool FixedPortsModel::_dataInitialised = false; @@ -241,6 +242,12 @@ GraphicsFunctionModelItem* FixedPortsModel::addGraphicItem(QUuid id,QString name item->bindProperty(pro); //绑定模型 //item->updateByProperty(); //使用模型更新自身 item->setHandle(this); + connect(item,&GraphicsFunctionModelItem::monitorParaRefSetted,this,[&](QUuid id,QString para){ + m_monitorParaRef[id] = para; + }); + connect(item->eventContext().data(),&GraphicsEventContext::panelVisibilityChanged,this,&FixedPortsModel::onPanelVisibilityChanged); + connect(item->eventContext().data(),&GraphicsEventContext::variableSet,this,&FixedPortsModel::onVariantSet); + connect(item->eventContext().data(),&GraphicsEventContext::scriptExecuted,this,&FixedPortsModel::onScriptExec); _graphicItem.insert(id,item); if(name.isEmpty()){ //如果不给名称则给个默认值 pro->setName("item_"+QString::number(_graphicItem.size())); @@ -789,6 +796,9 @@ QString FixedPortsModel::addNodeItem(QUuid id,QPointF pos,double width,double he } } }); + connect(item->eventContext().data(),&GraphicsEventContext::panelVisibilityChanged,this,&FixedPortsModel::onPanelVisibilityChanged); + connect(item->eventContext().data(),&GraphicsEventContext::variableSet,this,&FixedPortsModel::onVariantSet); + connect(item->eventContext().data(),&GraphicsEventContext::scriptExecuted,this,&FixedPortsModel::onScriptExec); } return pro->name(); } @@ -981,6 +991,9 @@ QString FixedPortsModel::addConnectLline(QUuid lineId,QUuid srcId,QUuid destId,Q pItem->setPropertyProxy(pProxy); addNodeItem(pItem->itemId(),pItem); pItem->bindProperty(pPro); + connect(pItem->eventContext().data(),&GraphicsEventContext::panelVisibilityChanged,this,&FixedPortsModel::onPanelVisibilityChanged); + connect(pItem->eventContext().data(),&GraphicsEventContext::variableSet,this,&FixedPortsModel::onVariantSet); + connect(pItem->eventContext().data(),&GraphicsEventContext::scriptExecuted,this,&FixedPortsModel::onScriptExec); } return pPro->name(); @@ -1754,6 +1767,21 @@ void FixedPortsModel::onSelectionChanged() } } +void FixedPortsModel::onPanelVisibilityChanged(const QString& panelName, bool show) +{ + _cavas->setHMIVisiblebyName(panelName,show); +} + +void FixedPortsModel::onVariantSet(QString varName,QVariant val) +{ + +} + +void FixedPortsModel::onScriptExec(QString script) +{ + +} + void FixedPortsModel::startHttpRequest() { if(_timer) @@ -1853,6 +1881,27 @@ void FixedPortsModel::updateMonitor(QMap> data) } } } + + // 构建查找表 + QHash connectParaLookup; + for (const auto& [uuid, items] : m_monitorPara.asKeyValueRange()) { + for (const MonitorItemAttributeInfo& item : items) { + if (!item.sConnectPara.isEmpty()) { + connectParaLookup.insert(item.sConnectPara, &item); + } + } + } + // 遍历m_monitorParaRef + for (const auto& [uuid, refValue] : m_monitorParaRef.asKeyValueRange()) { + if (auto graphicIt = _graphicItem.find(uuid); graphicIt != _graphicItem.end()) { + if (auto pItem = dynamic_cast(*graphicIt)) { //如果是文字对象 + if (auto itemIt = connectParaLookup.find(refValue); itemIt != connectParaLookup.end()) { + const MonitorItemAttributeInfo& matchedItem = *itemIt.value(); + pItem->setText(QString::number(matchedItem.mapValue.size()?matchedItem.mapValue.last():0)); + } + } + } + } } void FixedPortsModel::assignMeasureSymmetry(QMap& measurementMap) @@ -2511,6 +2560,11 @@ void FixedPortsModel::startAcceptData() } } + for(auto& paraRef:m_monitorParaRef){ //如果normalItem中未选择该属性,textItem引用了该属性,追加数据请求 + if(!lstTarget.contains(paraRef)) + lstTarget.append(paraRef); + } + QJsonObject obj; //构建开始请求 obj["action"] = "start"; QJsonArray arrMeasure; diff --git a/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp b/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp index 4bbb80d..80c610b 100644 --- a/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp +++ b/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp @@ -2,12 +2,15 @@ #include "baseProperty.h" #include "graphicsDataModel/fixedPortsModel.h" #include "baseItemPropertyProxy.h" +#include "graphicsItem/functionModelItem/graphicsEventContext.h" +#include "evetConfig/eventExecutor.h" GraphicsFunctionModelItem::GraphicsFunctionModelItem(QGraphicsItem *parent) : GraphicsProjectModelItem(parent) ,_pPropertyProxy(nullptr) { - + m_eventContext = QSharedPointer::create(); + m_eventExecutor = QSharedPointer(new EventExecutor()); } GraphicsFunctionModelItem::~GraphicsFunctionModelItem() @@ -43,13 +46,35 @@ void GraphicsFunctionModelItem::setMap(QMap boolMap) } } +EventList GraphicsFunctionModelItem::getEvents() const +{ + return EventList(m_events); +} + +void GraphicsFunctionModelItem::setEvents(const EventList& events) +{ + m_events = events.events; +} + +void GraphicsFunctionModelItem::triggerEvents(const QString& triggerType) +{ + for (const auto& event : m_events) { + if (event.trigger == triggerType) { + executeEvent(event); + } + } +} + +void GraphicsFunctionModelItem::executeEvent(const EventData& event) { + m_eventExecutor->execute(event, this); +} + void GraphicsFunctionModelItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(option) Q_UNUSED(widget) } - /********************************功能模item组*************************************/ GraphicsFunctionModelGroup::GraphicsFunctionModelGroup(QGraphicsItem *parent) diff --git a/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp b/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp index ef22987..4b49dc6 100644 --- a/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp +++ b/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp @@ -705,6 +705,7 @@ DataSourceType GraphicsProjectModelItem::getDataSourceType() const void GraphicsProjectModelItem::setDataSourceType(DataSourceType type) { _sourceType = type; + emit monitorParaRefSetted(getProperty()->uuid(),_sourceType.sPara); } QVariant GraphicsProjectModelItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value) diff --git a/diagramCavas/source/monitorPanel.cpp b/diagramCavas/source/monitorPanel.cpp index 064f1b4..16777db 100644 --- a/diagramCavas/source/monitorPanel.cpp +++ b/diagramCavas/source/monitorPanel.cpp @@ -22,6 +22,7 @@ #include "dataBase.h" #include "projectModelManager.h" #include "diagramCavas.h" +#include "extraPropertyManager.h" MonitorPanel::MonitorPanel(PowerEntity* pEntity,QWidget *parent,DiagramMode mode) : BaseDrawingPanel(pEntity,parent,mode) @@ -225,6 +226,9 @@ QJsonObject MonitorPanel::getDiagramInfo() auto para = serializeParaToJsonArray(_pModel->getMonitorPara()); //设定参数 obj["para"] = para; + auto paraRef = serializeUuidStringMap(_pModel->getMonitorParaRef()); + obj["paraRef"] = paraRef; + auto settingArr = serializeDisplayToJsonArray(_pModel->getMonitorDisplaySetting()); //显示参数 obj["displaySetting"] = settingArr; @@ -372,6 +376,37 @@ void MonitorPanel::loadNodes(QJsonObject obj) } } + QMap mapExtra; + ExtraPropertyManager* pExtra = _pModel->getCavas()->getExtraPropertyManager(); + if(pExtra){ + mapExtra = pExtra->geAlltProperty(); + } + + QJsonArray paraRefArr = obj["paraRef"].toArray(); + QMap mapParaRef; + bool resParaRef = deserializeUuidStringMap(paraRefArr,mapParaRef); + if(resParaRef){ + if(_pModel){ + _pModel->setMonitorParaRef(mapParaRef); + auto pItems = _pModel->getGraphicItems(); + for(auto& p:pItems){ + auto pPro = p->getProperty(); + if(pPro){ + QString sConnectPara = mapParaRef.value(pPro->uuid()); + for(auto& extra:mapExtra){ + if(extra.connect_para == sConnectPara){ + DataSourceType data; + data.sPara = sConnectPara; + data.sCode = extra.code; + p->setDataSourceType(data); //手动置回dataSource选中 + break; + } + } + } + } + } + } + _pModel->updateItemPropertyVisibleLst(); //更新item属性visible引用列表 QJsonArray displayArr = obj["displaySetting"].toArray(); @@ -958,6 +993,34 @@ bool MonitorPanel::deserializeParaFromJsonArray(const QJsonArray& jsonArray, return true; } +QJsonArray MonitorPanel::serializeUuidStringMap(const QMap& data) +{ + QJsonArray array; + for (auto it = data.constBegin(); it != data.constEnd(); ++it) { + QJsonObject obj; + obj["k"] = it.key().toString(); // k 表示 key + obj["v"] = it.value(); // v 表示 value + array.append(obj); + } + return array; +} + +bool MonitorPanel::deserializeUuidStringMap(const QJsonArray& jsonArray, QMap& result) +{ + result.clear(); + + for (const QJsonValue& val : jsonArray) { + if (!val.isObject()) continue; + + QJsonObject obj = val.toObject(); + QUuid uuid = QUuid::fromString(obj["k"].toString()); + if (!uuid.isNull()) { + result[uuid] = obj["v"].toString(); + } + } + + return true; +} QJsonArray MonitorPanel::serializeDisplayToJsonArray(const QMap>& data) const { diff --git a/diagramCavas/source/propertyType/propertyTypeCustomization_ConfigEventData.cpp b/diagramCavas/source/propertyType/propertyTypeCustomization_ConfigEventData.cpp new file mode 100644 index 0000000..9549679 --- /dev/null +++ b/diagramCavas/source/propertyType/propertyTypeCustomization_ConfigEventData.cpp @@ -0,0 +1,128 @@ +#include "propertyType/propertyTypeCustomization_ConfigEventData.h" +#include "QQuickDetailsViewLayoutBuilder.h" +#include "QPropertyHandle.h" +#include +#include +#include "propertyType/configEventData.h" +#include "QQuickFunctionLibrary.h" +#include "eventPropertyEditor.h" + +void PropertyTypeCustomization_ConfigEventData::customizeHeaderRow(QPropertyHandle* inPropertyHandle, QQuickDetailsViewRowBuilder* inBuilder) +{ + auto editorSlot = inBuilder->makeNameValueSlot(); + inPropertyHandle->setupNameEditor(editorSlot.first); + auto buttonItem = inBuilder->setupItem(editorSlot.second, R"( + import QtQuick + import QtQuick.Controls + + Item { + // 仅设置隐式大小 + implicitWidth: 180 + implicitHeight: 25 + + // 自定义信号 + signal customButtonClicked() + + // 让父容器控制宽度 + anchors.left: parent ? parent.left : undefined + anchors.right: parent ? parent.right : undefined + + // 设置文本的函数 + function setDisplayText(newText) { + displayText.text = newText; + } + + // 获取当前文本的函数 + function getDisplayText() { + return displayText.text; + } + + // 右侧功能按钮 + Button { + id: button + width: 25 + height: 25 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + + text: "..." + font.pixelSize: 9 + font.bold: true + + // 自定义按钮样式 + background: Rectangle { + color: button.down ? "#d0d0d0" : + button.hovered ? "#e0e0e0" : "#f0f0f0" + border.color: "#888" + border.width: 1 + radius: 4 + } + + // 点击时触发自定义信号 + onClicked: { + parent.customButtonClicked() + } + } + + // 文字显示区域 + Rectangle { + id: textArea + anchors { + left: parent.left + right: button.left + rightMargin: 5 + verticalCenter: parent.verticalCenter + } + height: 25 + + border.color: "#ccc" + border.width: 1 + radius: 4 + + Text { + id: displayText + anchors.fill: parent + anchors.margins: 5 + text: "datasource" + color: "#333" + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } + } + )"); + EventList curVal = inPropertyHandle->getVar().value(); + QStringList lstEvent; + for(auto& data:curVal.events){ + lstEvent.append(data.trigger); + } + QVariant curStr = QVariant(lstEvent.join(";")); + QMetaObject::invokeMethod(buttonItem, "setDisplayText", + Q_ARG(QVariant, curStr)); + + QQuickFunctionLibrary::connect(buttonItem, SIGNAL(customButtonClicked()), inPropertyHandle, [inPropertyHandle,buttonItem]() { + + EventList customType = inPropertyHandle->getVar().value(); + EventPropertyEditor dlg(customType); + if (dlg.exec() == QDialog::Accepted) { + EventList curData = dlg.getEvents(); + inPropertyHandle->setVar(QVariant::fromValue(curData)); + + QStringList lstEvent; + for(auto& data:curData.events){ + lstEvent.append(data.trigger); + } + QVariant curStr = QVariant(lstEvent.join(";")); + QMetaObject::invokeMethod(buttonItem, "setDisplayText", + Q_ARG(QVariant, curStr)); + } + }); +} + +void PropertyTypeCustomization_ConfigEventData::customizeChildren(QPropertyHandle* inPropertyHandle, QQuickDetailsViewLayoutBuilder* inBuilder) +{ + +} + diff --git a/diagramCavas/source/topologyManager.cpp b/diagramCavas/source/topologyManager.cpp index 3da35ed..eaf0570 100644 --- a/diagramCavas/source/topologyManager.cpp +++ b/diagramCavas/source/topologyManager.cpp @@ -771,6 +771,30 @@ PowerEntity* TopologyManager::findDiagram(const QString& id,ModelFunctionType fu return nullptr; } +PowerEntity* TopologyManager::findDiagramByName(const QString& name,ModelFunctionType funType) const +{ + if(funType == ModelFunctionType::ProjectModel){ + for(auto& pEntity:m_diagrams){ + if(pEntity->name() == name) + return pEntity; + } + } + else if(funType == ModelFunctionType::BaseModel){ + for(auto& pEntity:m_baseDiagrams){ + if(pEntity->name() == name) + return pEntity; + } + } + else if(funType == ModelFunctionType::RuntimeModel){ + for(auto& pEntity:m_monitorDiagrams){ + if(pEntity->name() == name) + return pEntity; + } + } + + return nullptr; +} + bool TopologyManager::deleteDiagram(const QString& id,ModelFunctionType funType) { if(funType == ModelFunctionType::ProjectModel){