diff --git a/diagramCavas/include/baseDrawingPanel.h b/diagramCavas/include/baseDrawingPanel.h index 94de1c2..d777694 100644 --- a/diagramCavas/include/baseDrawingPanel.h +++ b/diagramCavas/include/baseDrawingPanel.h @@ -51,6 +51,10 @@ public: PowerEntity* getEntity() {return _pEntity;} BasePannelPropertyProxy* getPropertyProxy(); + + void moveItemsAlignment(Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft, + const QMarginsF& margins = QMarginsF(0, 0, 0, 0)); //整体移动函数(会破坏对象结构,只用来预览) + void centerOnTopLeft(); //聚焦到左上角 signals: void panelDelete(const QString&,int); protected: diff --git a/diagramCavas/include/createHMIdlg.h b/diagramCavas/include/createHMIdlg.h index d389bef..0d9f5ae 100644 --- a/diagramCavas/include/createHMIdlg.h +++ b/diagramCavas/include/createHMIdlg.h @@ -7,6 +7,8 @@ QT_BEGIN_NAMESPACE namespace Ui { class createHMIdlg; } QT_END_NAMESPACE +class DiagramCavasPrivate; + class CreateHMIdlg : public QDialog { Q_OBJECT @@ -16,6 +18,7 @@ public: void initial(); void showDlg(); + void setCavasPtr(DiagramCavasPrivate* p){_pCavasPtr = p;} signals: void createHMI(QString,QString,int type = 0); //HMI名称,系统图名称,模板类型 void createCustomHMI(QString,QString,int type = 0); //HMI名称,系统图名称,模板类型 @@ -23,8 +26,12 @@ public slots: void onSaveClicked(); void onCancelClicked(); void onCustomClicked(); +private: + void showInfoTip(const QString& text, int durationMs = 3000); private: Ui::createHMIdlg *ui; + QTimer* m_timer = nullptr; + DiagramCavasPrivate* _pCavasPtr = nullptr; }; #endif diff --git a/diagramCavas/include/customHMIGenerateDlg.h b/diagramCavas/include/customHMIGenerateDlg.h index 4cc9ec0..27ce48a 100644 --- a/diagramCavas/include/customHMIGenerateDlg.h +++ b/diagramCavas/include/customHMIGenerateDlg.h @@ -12,6 +12,7 @@ class PowerEntity; class DiagramCavas; class CustomHMIList; struct HierarchyItem; +class DiagramCavasPrivate; class CustomHMIGenerateDlg : public QDialog { @@ -22,12 +23,15 @@ public: void initial(); void showDlg(QString,QString,int); //hmi名,系统图名,模板 + void setCavasPtr(DiagramCavasPrivate* p){_pCavasPtr = p;} signals: void backCreateHMI(); //退回初始界面信号 public slots: void onGenerateClicked(); void onBackClicked(); void onPreviewHMI(QList); +private: + void showInfoTip(const QString& text, int durationMs = 3000); private: Ui::customHMIGenerateDlg *ui; SelectPanel* _pOperatePanel; //操作界面 @@ -35,7 +39,10 @@ private: PowerEntity* _pPe; PowerEntity* _pOe; DiagramCavas* _pCanvas = nullptr; + DiagramCavasPrivate* _pCavasPtr = nullptr; CustomHMIList* _pItemList; + QList _tempLst; + QTimer* m_timer = nullptr; }; #endif diff --git a/diagramCavas/include/customHMIList.h b/diagramCavas/include/customHMIList.h index 54099e7..c9de135 100644 --- a/diagramCavas/include/customHMIList.h +++ b/diagramCavas/include/customHMIList.h @@ -39,6 +39,7 @@ private: QStandardItemModel* _modelAll; //图中所有item // 存储间隔名称到树节点的映射,提高查找效率 QHash m_mapBayItems; + bool m_isProgrammaticChange = false; //程序设置标志 }; #endif diff --git a/diagramCavas/include/diagramCavas.h b/diagramCavas/include/diagramCavas.h index 79d1d80..22661c9 100644 --- a/diagramCavas/include/diagramCavas.h +++ b/diagramCavas/include/diagramCavas.h @@ -115,7 +115,7 @@ public slots: void updateHMIlstFromDB(); //从数据库更新HMI列表 - //QMap> getMapMonitor() {return m_mapMonitorPanel;} + QMdiSubWindow* getSubWindow(const QString&); void onTargetSelected(QObject*); //选中事件(属性显示) protected: diff --git a/diagramCavas/include/diagramCavas_p.h b/diagramCavas/include/diagramCavas_p.h index ff1df0d..d721cf2 100644 --- a/diagramCavas/include/diagramCavas_p.h +++ b/diagramCavas/include/diagramCavas_p.h @@ -49,7 +49,7 @@ public: PluginItemFactory* m_itemFactory = nullptr; QMap m_pluginInfo; QMdiArea* m_mdiArea = nullptr; - int _curMode = 0; + int _curMode = 0; //0编辑1运行 // 私有方法 void initialImpl(); @@ -68,6 +68,7 @@ public: void updateHMIListFormDB(); //从DB更新HMI列表(page中load) void deletePanel(const QString& name,int nType); void setCurMode(int); + int getCurMode() const {return _curMode;} //显示属性相关 void showPropertyDlgImpl(); // 显示属性页 diff --git a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h index 350c0a1..e3b90aa 100644 --- a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h +++ b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h @@ -111,6 +111,9 @@ public: QMap& getMonitorParaRef(){return m_monitorParaRef;} void setMonitorRelation(QList lst){m_lstMonitorRelation = lst;} QList getMonitorRelation() {return m_lstMonitorRelation;} + void setBayHierachy(QList lst) {m_bayHierachy = lst;} + void setItemHierachy(QList lst) {m_itemHierachy = lst;} + void activePanelHierachy(); //激活当前界面的层级关系 void monitorItemSelected(QUuid); //运行时item选中事件 void monitorItemDetailAttr(QUuid); //显示属性详情 @@ -127,6 +130,7 @@ public: QMap>& getMonitorDisplaySetting(){return m_monitorDisplaySetting;} void previewHMI(SelectPanel* pPreview,QList); //customHMI 生成预览 + void customGenerateHMI(QString,QPair,QList); //自定义生成HMI QList& getHMIimageRef(){return _HMIimageRef;} QList& getHMICustomImageRef(){return _HMICustomImageRef;} int imageRefExist(QString model,QByteArray hash256); @@ -207,7 +211,9 @@ private: QMap m_monitorParaRef; //监控参数的引用关系(文字item等) QMap>> m_monitorStateMap; //元件状态对照表 > QMap> m_monitorDisplaySetting; //元件设置 - QList m_lstMonitorRelation; //监控item层级关系 + QList m_lstMonitorRelation; //监控item层级关系(暂无使用) + QList m_bayHierachy; //间隔层级信息 + QList m_itemHierachy; //元件层级信息 ItemPropertyDlg* m_curPropertyDlg; QTimer* m_dataTimer; //获取数据的定时器 diff --git a/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h b/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h index 1e9a4c1..3e0d49e 100644 --- a/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h +++ b/diagramCavas/include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h @@ -49,8 +49,10 @@ class GraphicsFunctionModelGroup : public GraphicsFunctionModelItem // Q_OBJECT public: GraphicsFunctionModelGroup(QGraphicsItem *parent); + GraphicsFunctionModelGroup(const GraphicsFunctionModelGroup&); virtual ~GraphicsFunctionModelGroup(); virtual void addItem(GraphicsFunctionModelItem* item); + virtual GraphicsFunctionModelGroup* clone() const override; virtual void updateLayout(); virtual void setLayout(int n) {m_direction = n;} virtual void setGroupType(int n) {_groupType = n;} diff --git a/diagramCavas/include/graphicsItem/pluginSvgItemWrapper.h b/diagramCavas/include/graphicsItem/pluginSvgItemWrapper.h index f3d2715..da25395 100644 --- a/diagramCavas/include/graphicsItem/pluginSvgItemWrapper.h +++ b/diagramCavas/include/graphicsItem/pluginSvgItemWrapper.h @@ -12,6 +12,7 @@ class PluginSvgItemWrapper : public ElectricFunctionModelSvgItem public: explicit PluginSvgItemWrapper(ICanvasItem *pluginItem, QGraphicsItem *parent = nullptr); + PluginSvgItemWrapper(ICanvasItem *pluginItem,const PluginSvgItemWrapper& obj); virtual ~PluginSvgItemWrapper(); virtual void setImage_1(QFileInfo) override; diff --git a/diagramCavas/include/monitorPanel.h b/diagramCavas/include/monitorPanel.h index 188e326..f7585b8 100644 --- a/diagramCavas/include/monitorPanel.h +++ b/diagramCavas/include/monitorPanel.h @@ -37,6 +37,7 @@ public: void initDisplaySetting(); //初始化显示状态设置 MonitorConfigDlg* getMonitorConfigDlg() {return _pConfigDlg;} + void setToobarlVisible(bool); //设置运行模式 public: //对层级关系的序列化与反序列化 QJsonArray serializeRelationToJsonArray(const QList& data) const; @@ -61,6 +62,7 @@ protected: void closeEvent(QCloseEvent *closeEvent) override; private: void createToolBar(); + QGraphicsItem* findCentralItem(); private: QString _sParentPage; //派生自哪个工程 QToolBar* _toolBar; diff --git a/diagramCavas/include/util/baseSelector.h b/diagramCavas/include/util/baseSelector.h index 3d6003a..6974c09 100644 --- a/diagramCavas/include/util/baseSelector.h +++ b/diagramCavas/include/util/baseSelector.h @@ -70,6 +70,8 @@ public: FixedPortsModel* getModel() {return _model;} void updateConnectLineByTopology(QList); //通过拓扑关系更新位置 + // 辅助函数:根据已知点计算缺失点的位置 + QPointF calculateMissingPointByKnownPoint(const QPointF& knownPoint, const QRectF& itemSceneRect, qint32 offset, bool isFromPoint); signals: void setWorkingSelector(SelectorType); protected: diff --git a/diagramCavas/source/baseDrawingPanel.cpp b/diagramCavas/source/baseDrawingPanel.cpp index 648cbf4..52a2b76 100644 --- a/diagramCavas/source/baseDrawingPanel.cpp +++ b/diagramCavas/source/baseDrawingPanel.cpp @@ -83,6 +83,56 @@ BasePannelPropertyProxy* BaseDrawingPanel::getPropertyProxy() return _pPropertyProxy.data(); } +void BaseDrawingPanel::moveItemsAlignment(Qt::Alignment alignment,const QMarginsF& margins) +{ + QList items = m_pGraphicsScene->items(); + if (items.isEmpty() || !m_pGraphicsScene) return; + + // 1. 创建组 + QGraphicsItemGroup* group = m_pGraphicsScene->createItemGroup(items); + + // 2. 获取边界矩形 + QRectF groupRect = group->boundingRect(); + QRectF sceneRect = m_pGraphicsScene->sceneRect(); + + // 3. 计算新位置 + QPointF targetPos = group->pos(); + + // 水平对齐 + if (alignment & Qt::AlignLeft) { + targetPos.setX(sceneRect.left() + margins.left()); + } else if (alignment & Qt::AlignRight) { + targetPos.setX(sceneRect.right() - groupRect.width() - margins.right()); + } else if (alignment & Qt::AlignHCenter) { + targetPos.setX(sceneRect.center().x() - groupRect.width() / 2); + } + + // 垂直对齐 + if (alignment & Qt::AlignTop) { + targetPos.setY(sceneRect.top() + margins.top()); + } else if (alignment & Qt::AlignBottom) { + targetPos.setY(sceneRect.bottom() - groupRect.height() - margins.bottom()); + } else if (alignment & Qt::AlignVCenter) { + targetPos.setY(sceneRect.center().y() - groupRect.height() / 2); + } + + // 4. 计算偏移量 + QPointF offset = targetPos - groupRect.topLeft(); + group->setPos(group->pos() + offset); + + // 5. 取消分组 + m_pGraphicsScene->destroyItemGroup(group); +} + +void BaseDrawingPanel::centerOnTopLeft() { + // 获取场景左上角 + QRectF sceneRect = m_pGraphicsScene->sceneRect(); + QPointF topLeft = sceneRect.topLeft(); + + // 将视图中心对准左上角 + m_pGraphicsView->centerOn(topLeft); +} + SelectorManager* BaseDrawingPanel::selectorManager() const { if(m_pSelectorManager) diff --git a/diagramCavas/source/createHMIdlg.cpp b/diagramCavas/source/createHMIdlg.cpp index c4ff278..32b6d34 100644 --- a/diagramCavas/source/createHMIdlg.cpp +++ b/diagramCavas/source/createHMIdlg.cpp @@ -2,6 +2,8 @@ #include "common/frontend/monitor_item.h" #include "dataBase.h" #include "ui_createHMIdlg.h" +#include "diagramCavas_p.h" +#include CreateHMIdlg::CreateHMIdlg(QWidget *parent) : QDialog(parent) @@ -22,6 +24,10 @@ void CreateHMIdlg::initial() connect(ui->btn_cancel,&QPushButton::clicked,this,&CreateHMIdlg::onCancelClicked); connect(ui->btn_ok,&QPushButton::clicked,this,&CreateHMIdlg::onSaveClicked); connect(ui->btn_custom,&QPushButton::clicked,this,&CreateHMIdlg::onCustomClicked); + + m_timer = new QTimer(this); + m_timer->setSingleShot(true); + connect(m_timer, &QTimer::timeout, ui->label_info, &QLabel::hide); } void CreateHMIdlg::showDlg() @@ -49,7 +55,37 @@ void CreateHMIdlg::onCustomClicked() void CreateHMIdlg::onSaveClicked() { - QString sName = ui->cb_structure->currentText(); - emit createHMI(ui->lineEdit->text(),sName); + auto lstHMI = DataBase::GetInstance()->getAllHMI(); + QString sSysName = ui->cb_structure->currentText(); //系统图名 + QString sName = ui->lineEdit->text(); + + if(sName.isEmpty()){ + showInfoTip("名称不能为空"); + return; + } + if(_pCavasPtr->m_mapMonitorPanel.contains(sName)){ + showInfoTip("名称已存在"); + return; + } + + for(auto& info:lstHMI){ + if(sName == info.name || sName == info.tag) + { + showInfoTip("名称已存在"); + return ; + } + } + emit createHMI(sName,sSysName); hide(); } + +void CreateHMIdlg::showInfoTip(const QString& text,int durationMs) +{ + ui->label_info->setText(text); + ui->label_info->show(); + + // 停止之前的定时器 + m_timer->stop(); + // 重新启动定时器 + m_timer->start(durationMs); +} diff --git a/diagramCavas/source/customHMIGenerateDlg.cpp b/diagramCavas/source/customHMIGenerateDlg.cpp index 3aa039f..bfc5d33 100644 --- a/diagramCavas/source/customHMIGenerateDlg.cpp +++ b/diagramCavas/source/customHMIGenerateDlg.cpp @@ -5,6 +5,7 @@ #include "diagramCavas.h" #include "customHMIList.h" #include "ui_customHMIGenerateDlg.h" +#include "diagramCavas_p.h" #include CustomHMIGenerateDlg::CustomHMIGenerateDlg(QWidget *parent) @@ -17,6 +18,7 @@ CustomHMIGenerateDlg::CustomHMIGenerateDlg(QWidget *parent) ,_pItemList(nullptr) { ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); _pCanvas = dynamic_cast(parent); this->setWindowFlags(Qt::FramelessWindowHint | windowFlags()); initial(); @@ -56,6 +58,10 @@ void CustomHMIGenerateDlg::initial() connect(_pOperatePanel->getModelController(),&FixedPortsModel::updateCurrentItems,_pItemList,&CustomHMIList::onUpdateItems); connect(_pOperatePanel->getModelController(),&FixedPortsModel::itemSelected,_pItemList,&CustomHMIList::onSelectItems); connect(_pItemList,&CustomHMIList::previewHMI,this,&CustomHMIGenerateDlg::onPreviewHMI); + + m_timer = new QTimer(this); + m_timer->setSingleShot(true); + connect(m_timer, &QTimer::timeout, ui->label_info, &QLabel::hide); } void CustomHMIGenerateDlg::showDlg(QString sHmi,QString sSys,int nModel) @@ -69,13 +75,49 @@ void CustomHMIGenerateDlg::showDlg(QString sHmi,QString sSys,int nModel) } _pOperatePanel->getModelController()->clearCurItems(); //先清空 + _pPreviewPanel->getModelController()->clearCurItems(); QJsonObject context = db->getHMIContextByTag(sSys); _pOperatePanel->loadNodes(context); + _pOperatePanel->centerOnTopLeft(); } void CustomHMIGenerateDlg::onGenerateClicked() { - hide(); + auto lstHMI = DataBase::GetInstance()->getAllHMI(); + QString sName = ui->le_hmiName->text(); + + if(sName.isEmpty()){ + showInfoTip("名称不能为空"); + return; + } + if(_pCavasPtr->m_mapMonitorPanel.contains(sName)){ + showInfoTip("名称已存在"); + return; + } + for(auto& info:lstHMI){ + if(sName == info.name || sName == info.tag) + { + showInfoTip("名称已存在"); + return ; + } + } + + int nWidth = 0; + int nHeight = 0; + QStringList lstSize = ui->cb_size->currentText().split("*"); + if(lstSize.size() == 2){ + nWidth = lstSize.first().toInt(); + nHeight = lstSize.last().toInt(); + } + + if(_tempLst.size() > 0){ + QObject::connect(_pOperatePanel->getModelController(), &FixedPortsModel::updateTopologyItems, _pCanvas,&DiagramCavas::onSignal_updateTopology); + _pOperatePanel->getModelController()->customGenerateHMI(ui->le_hmiName->text(),qMakePair(nWidth,nHeight),_tempLst); + hide(); + } + else{ + showInfoTip("未选中生成对象"); + } } void CustomHMIGenerateDlg::onBackClicked() @@ -88,4 +130,17 @@ void CustomHMIGenerateDlg::onPreviewHMI(QList lst) { _pPreviewPanel->clearItems(); _pOperatePanel->getModelController()->previewHMI(_pPreviewPanel,lst); + _pPreviewPanel->moveItemsAlignment(Qt::AlignHCenter|Qt::AlignVCenter); + _tempLst = lst; +} + +void CustomHMIGenerateDlg::showInfoTip(const QString& text,int durationMs) +{ + ui->label_info->setText(text); + ui->label_info->show(); + + // 停止之前的定时器 + m_timer->stop(); + // 重新启动定时器 + m_timer->start(durationMs); } diff --git a/diagramCavas/source/customHMIList.cpp b/diagramCavas/source/customHMIList.cpp index 5e0acf6..ac8c8d2 100644 --- a/diagramCavas/source/customHMIList.cpp +++ b/diagramCavas/source/customHMIList.cpp @@ -56,6 +56,10 @@ void CustomHMIList::onUpdateItems(QList lst,bool refresh) pBayItem->setData(curItem.nCategory, Qt::UserRole+1); // 存储类别 pBayItem->setData(curItem.nEquipType, Qt::UserRole+2); // 存储设备类型 pBayItem->setData(curItem.uid, Qt::UserRole+3); // 存储UUID + pBayItem->setData(curItem.grid, Qt::UserRole+4); //grid + pBayItem->setData(curItem.zone, Qt::UserRole+5); //zone + pBayItem->setData(curItem.station, Qt::UserRole+6); //station + pBayItem->setData(curItem.sVoltageLevel, Qt::UserRole+7); //电压层级 // 存储到缓存中 m_mapBayItems[curItem.sName] = pBayItem; @@ -99,6 +103,7 @@ void CustomHMIList::onUpdateItems(QList lst,bool refresh) void CustomHMIList::onSelectItems(QList lst) { + m_isProgrammaticChange = true; resetSelect(); for(auto& info:lst){ QModelIndex itemIndex = findIndex(_modelAll,info.item.uid,Qt::UserRole+3); @@ -109,6 +114,7 @@ void CustomHMIList::onSelectItems(QList lst) } } generatePreview(); + m_isProgrammaticChange = false; } void CustomHMIList::generatePreview() @@ -118,17 +124,38 @@ void CustomHMIList::generatePreview() for(auto& pItem:lstItem){ HierarchyItem info; auto pParent = pItem->parent(); + if(pParent){ + // 设置父节点信息 info.parent.nCategory = pParent->data(Qt::UserRole+1).toInt(); info.parent.nEquipType = pParent->data(Qt::UserRole+2).toInt(); info.parent.uid = pParent->data(Qt::UserRole+3).toUuid(); info.parent.sName = pParent->text(); + + // 如果是间隔节点(nCategory==1),还需要获取其附加属性 + if(info.parent.nCategory == 1){ + info.parent.grid = pParent->data(Qt::UserRole+4).toString(); + info.parent.zone = pParent->data(Qt::UserRole+5).toString(); + info.parent.station = pParent->data(Qt::UserRole+6).toString(); + info.parent.sVoltageLevel = pParent->data(Qt::UserRole+7).toString(); + } } + + // 设置当前项信息 info.item.nCategory = pItem->data(Qt::UserRole+1).toInt(); info.item.nEquipType = pItem->data(Qt::UserRole+2).toInt(); info.item.uid = pItem->data(Qt::UserRole+3).toUuid(); info.item.sName = pItem->text(); + // 如果是间隔节点,还需要获取其附加属性 + if(info.item.nCategory == 1){ + info.item.grid = pItem->data(Qt::UserRole+4).toString(); + info.item.zone = pItem->data(Qt::UserRole+5).toString(); + info.item.station = pItem->data(Qt::UserRole+6).toString(); + info.item.sVoltageLevel = pItem->data(Qt::UserRole+7).toString(); + } + + // 获取所有子节点 auto lstChild = getAllChildren(pItem); for(auto &child:lstChild){ HierarchyStructItem stru; @@ -136,6 +163,7 @@ void CustomHMIList::generatePreview() stru.nEquipType = child->data(Qt::UserRole+2).toInt(); stru.uid = child->data(Qt::UserRole+3).toUuid(); stru.sName = child->text(); + info.subList.append(stru); } lst.append(info); @@ -157,6 +185,11 @@ void CustomHMIList::onItemChanged(QStandardItem *item) Qt::CheckState newState = item->checkState(); // 设置所有子项与父项相同的状态 setChildrenCheckState(item, newState); + + // 只在非程序设置时发送信号 + if (!m_isProgrammaticChange) { + generatePreview(); + } } _tree->repaint(); diff --git a/diagramCavas/source/diagramCavas.cpp b/diagramCavas/source/diagramCavas.cpp index 5f736da..0861cd4 100644 --- a/diagramCavas/source/diagramCavas.cpp +++ b/diagramCavas/source/diagramCavas.cpp @@ -467,3 +467,9 @@ void DiagramCavas::updateHMIlstFromDB() Q_D(DiagramCavas); d->updateHMIFromDB(); } + +QMdiSubWindow* DiagramCavas::getSubWindow(const QString& name) +{ + Q_D(DiagramCavas); + return d->getSubWindow(name); +} diff --git a/diagramCavas/source/diagramCavas_p.cpp b/diagramCavas/source/diagramCavas_p.cpp index 9483c05..3fa945f 100644 --- a/diagramCavas/source/diagramCavas_p.cpp +++ b/diagramCavas/source/diagramCavas_p.cpp @@ -155,11 +155,13 @@ void DiagramCavasPrivate::initialImpl() QObject::connect(_createHMIDlg, &CreateHMIdlg::createCustomHMI, q, [this](QString sName,QString sSys,int nModel){ _customCreateHMIDlg->showDlg(sName,sSys,nModel); }); + _createHMIDlg->setCavasPtr(this); _customCreateHMIDlg = new CustomHMIGenerateDlg(q); QObject::connect(_customCreateHMIDlg, &CustomHMIGenerateDlg::backCreateHMI, q, [this](){ _createHMIDlg->showDlg(); }); + _customCreateHMIDlg->setCavasPtr(this); // 13. 从数据库更新HMI列表 q->updateHMIlstFromDB(); @@ -191,6 +193,11 @@ void DiagramCavasPrivate::initialImpl() QHBoxLayout* mainLayout = new QHBoxLayout(q); mainLayout->addWidget(m_mdiArea, 1); // 主工作区占主要空间 mainLayout->addWidget(_pPropertyDlg, 0); // 属性栏占次要空间 + + QTimer::singleShot(100, q, [this]() { + updateCornerPos(); + }); + } void DiagramCavasPrivate::removePanel(PowerEntity* pEntity) @@ -441,6 +448,18 @@ void DiagramCavasPrivate::setCurMode(int nMode) else { // 编辑模式 q->hidePropertyDlg(); } + + for(auto& pair:m_mapMonitorPanel){ + auto pPanel = pair.first; + if(pPanel){ + if(nMode == 0){ //编辑 + pPanel->setToobarlVisible(true); + } + else{ //运行 + pPanel->setToobarlVisible(false); + } + } + } } void DiagramCavasPrivate::initPropertyPage() @@ -460,35 +479,6 @@ void DiagramCavasPrivate::initPropertyPage() void DiagramCavasPrivate::showPropertyDlgImpl() { - /*Q_Q(DiagramCavas); - - // 确保属性页面已初始化 - initPropertyPage(); - - // 确保属性对话框已创建 - if (_pPropertyDlg == nullptr) { - _pPropertyDlg = new PropertyDlg(q->parentWidget()); - _pPropertyDlg->setWindowTitle("属性设置"); - _pPropertyDlg->setModal(false); // 非模态对话框 - - // 连接对话框关闭信号 - QObject::connect(_pPropertyDlg, &PropertyDlg::finished, q, [this]() { - // 对话框关闭时的处理 - qDebug() << "Property dialog closed"; - }); - } - - // 设置内容 - _pPropertyDlg->show(); - _pPropertyDlg->setContent(_pPropertyPage);*/ - //_pPropertyPage->setObject(q_ptr); - - // 居中显示 - //centerPropertyDialogOnScreen(); - - // 激活窗口 - //_pPropertyDlg->raise(); - //_pPropertyDlg->activateWindow(); Q_Q(DiagramCavas); initPropertyPage(); @@ -1086,6 +1076,13 @@ bool DiagramCavasPrivate::createAndLoadMonitor(PowerEntity* p, const QJsonObject QJsonObject pageAttr = context["pageAttr"].toObject(); applyPageGeometry(panel, subWindow, pageAttr); } + + if(_curMode == 0){ //编辑 + panel->setToobarlVisible(true); + } + else{ + panel->setToobarlVisible(false); + } } else { qDebug() << "No context data for monitor, using default:" << monitorName; } @@ -1108,6 +1105,7 @@ bool DiagramCavasPrivate::loadExistingMonitor(const QString& name) // 显示面板 panel->show(); + panel->getModelController()->activePanelHierachy(); //激活当前层级关系 // 设置为活动子窗口 Q_Q(DiagramCavas); diff --git a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp index 035d197..d486f4a 100644 --- a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp +++ b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp @@ -2529,6 +2529,12 @@ void FixedPortsModel::generateMonitorConfig(MonitorPanel* pPanel) } } +void FixedPortsModel::activePanelHierachy() +{ + emit updateTopologyItems(m_bayHierachy, true,true); + emit updateTopologyItems(m_itemHierachy, false,true); +} + void FixedPortsModel::monitorItemSelected(QUuid uid) { auto pMonitor = dynamic_cast(_widget); @@ -2776,8 +2782,97 @@ void FixedPortsModel::previewHMI(SelectPanel* pPanel,QList lst) auto pSubWin = map.value(sPage).second; pSubWin->resize(itemsRect.width(),itemsRect.height()); }*/ + //pPanel->getView()->fitInView(itemsRect, Qt::KeepAspectRatio); + } + } + } +} + +void FixedPortsModel::customGenerateHMI(QString sPage,QPair size,QList lst) +{ + MonitorPanel* pPanel = nullptr; + if(_cavas){ + DiagramInfo info; + info.id = QUuid::createUuid(); + info.sName = sPage; + info.sTag = sPage; + info.sBasePageName = _pageName; + info.parentId = _pEntity->id(); + _cavas->onSignal_createDiagram(info,DiagramMode::DM_run); + pPanel = _cavas->getMonitorPanel(sPage); + pPanel->getModelController()->setMonitorRelation(lst); + + QList lstFirst; + QList lstSecond; + for(auto& itemInfo:lst) //第一次循环处理间隔 + { + if(itemInfo.item.nCategory == 1){ //间隔 + if(_bayItem.contains(itemInfo.item.uid)){ + auto pBay = _bayItem.value(itemInfo.item.uid); + BayProperty* pPro = dynamic_cast(pBay->getProperty()); + if(pPro){ + pPanel->getModelController()->addBayByData(pPro); + } + } + lstFirst.append(itemInfo); //在lst插入时判断重复 + } + } + + for(auto& itemInfo:lst) + { + if(itemInfo.item.nCategory == 0){ //设备 + if(_nodeItem.contains(itemInfo.item.uid)){ + auto pItem = _nodeItem.value(itemInfo.item.uid); + BaseProperty* pPro = dynamic_cast(pItem->getProperty()); + if(pPro){ + auto pNewItem = pItem->clone(); + if(pPro->type() == 8){ + auto pLine = dynamic_cast(pNewItem); + if(pLine) + pLine->calculatePath(); + } + else{ + pNewItem->updateItem(); + } + + if(pNewItem && pPanel){ + pNewItem->bindProperty(pPro); + pNewItem->updateHandles(); + pNewItem->updateByProperty(); //使用模型更新自身 + pPanel->getModelController()->addNodeItem(pPro->uuid(),pNewItem); + pPanel->getScene()->addItem(pNewItem); //绑定模型 + } + } + lstSecond.append(itemInfo); + } + } + } + + if(pPanel){ + if (!pPanel->getScene()->items().isEmpty()) { + //pPanel->moveItemsAlignment(); + QRectF itemsRect = pPanel->getScene()->itemsBoundingRect(); + itemsRect.adjust(-100, -100, 100, 100); + + auto pSubWin = _cavas->getSubWindow(sPage); + if(pSubWin) + pSubWin->resize(size.first,size.second); pPanel->getView()->fitInView(itemsRect, Qt::KeepAspectRatio); } + + emit pPanel->getModelController()->monitorCreated(_pageName,qMakePair(sPage,info.id.toUuid())); + + generateMonitorConfig(pPanel); + + emit updateTopologyItems(lstFirst, true,true); + emit updateTopologyItems(lstSecond, false,true); + pPanel->getModelController()->setBayHierachy(lstFirst); //保存生成的间隔层级 + pPanel->getModelController()->setItemHierachy(lstSecond); //保存生成的对象层级 + + pPanel->initDisplayState(); + pPanel->initDisplaySetting(); + + _cavas->onSignal_createHMI(sPage,info.id.toUuid()); } } } diff --git a/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItem.cpp b/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItem.cpp index 25789a7..f0ef79c 100644 --- a/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItem.cpp +++ b/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItem.cpp @@ -120,6 +120,16 @@ void ElectricFunctionModelSvgItem::paint(QPainter* painter, const QStyleOptionGr { m_pRender->render(painter,m_boundingRect); } + else{ + painter->setBrush(QBrush(QColor(248, 248, 248))); // 浅灰白 + // 2. 设置虚线画笔 + QPen pen(QColor(160, 160, 160)); + pen.setStyle(Qt::DashLine); + pen.setWidth(1); + painter->setPen(pen); + // 3. 绘制基础矩形 + painter->drawRoundedRect(boundingRect(), 2, 2); + } } painter->setPen(m_pen); diff --git a/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemCT.cpp b/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemCT.cpp index 1653b6d..ba87dcf 100644 --- a/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemCT.cpp +++ b/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemCT.cpp @@ -93,25 +93,34 @@ void ElectricFunctionModelSvgItemCT::paint(QPainter* painter, const QStyleOption } } else{ - if (!m_pRender || !m_pRender->isValid()) - return; - - // 绘制第一个图形 - if(_itemType == 1){ - QRectF rect1(m_boundingRect.x(), m_boundingRect.y(), singleWidth, m_boundingRect.height()); - m_pRender->render(painter, rect1); - - // 绘制第二个图形 - QRectF rect2(m_boundingRect.x() + singleWidth, m_boundingRect.y(), singleWidth, m_boundingRect.height()); - m_pRender->render(painter, rect2); - - // 绘制第三个图形 - QRectF rect3(m_boundingRect.x() + 2 * singleWidth, m_boundingRect.y(), singleWidth, m_boundingRect.height()); - m_pRender->render(painter, rect3); + if (!m_pRender || !m_pRender->isValid()){ + painter->setBrush(QBrush(QColor(230, 230, 230))); // 浅灰白,未设置图片 + // 2. 设置虚线画笔 + QPen pen(QColor(160, 160, 160)); + pen.setStyle(Qt::DashLine); + pen.setWidth(1); + painter->setPen(pen); + // 3. 绘制基础矩形 + painter->drawRoundedRect(boundingRect(), 2, 2); } - else if(_itemType == 0){ - QRectF rect(m_boundingRect.x() + singleWidth, m_boundingRect.y(), singleWidth, m_boundingRect.height()); - m_pRender->render(painter, rect); + else{ + // 绘制第一个图形 + if(_itemType == 1){ + QRectF rect1(m_boundingRect.x(), m_boundingRect.y(), singleWidth, m_boundingRect.height()); + m_pRender->render(painter, rect1); + + // 绘制第二个图形 + QRectF rect2(m_boundingRect.x() + singleWidth, m_boundingRect.y(), singleWidth, m_boundingRect.height()); + m_pRender->render(painter, rect2); + + // 绘制第三个图形 + QRectF rect3(m_boundingRect.x() + 2 * singleWidth, m_boundingRect.y(), singleWidth, m_boundingRect.height()); + m_pRender->render(painter, rect3); + } + else if(_itemType == 0){ + QRectF rect(m_boundingRect.x() + singleWidth, m_boundingRect.y(), singleWidth, m_boundingRect.height()); + m_pRender->render(painter, rect); + } } } } diff --git a/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemPT.cpp b/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemPT.cpp index 8e0a285..b8d4a03 100644 --- a/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemPT.cpp +++ b/diagramCavas/source/graphicsItem/functionModelItem/electricFunctionModelSvgItemPT.cpp @@ -66,8 +66,18 @@ void ElectricFunctionModelSvgItemPT::paint(QPainter* painter, const QStyleOption } else{ if (!m_pRender || !m_pRender->isValid()) - return; - m_pRender->render(painter, m_boundingRect); + { + painter->setBrush(QBrush(QColor(230, 230, 230))); // 浅灰白,未设置图片 + // 2. 设置虚线画笔 + QPen pen(QColor(160, 160, 160)); + pen.setStyle(Qt::DashLine); + pen.setWidth(1); + painter->setPen(pen); + // 3. 绘制基础矩形 + painter->drawRoundedRect(boundingRect(), 2, 2); + } + else + m_pRender->render(painter, m_boundingRect); } } diff --git a/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp b/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp index 6889fda..b1d92f0 100644 --- a/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp +++ b/diagramCavas/source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp @@ -95,11 +95,29 @@ GraphicsFunctionModelGroup::GraphicsFunctionModelGroup(QGraphicsItem *parent) } +GraphicsFunctionModelGroup::GraphicsFunctionModelGroup(const GraphicsFunctionModelGroup& obj) + :GraphicsFunctionModelItem(obj) +{ + m_direction = obj.m_direction; + m_spacing = obj.m_spacing; + _groupType = obj.m_spacing; + + for(auto &pItem:obj.m_childItems){ + auto newItem = pItem->clone(); + m_childItems.append(newItem); + } +} + GraphicsFunctionModelGroup::~GraphicsFunctionModelGroup() { } +GraphicsFunctionModelGroup* GraphicsFunctionModelGroup::clone() const +{ + return new GraphicsFunctionModelGroup(*this); +} + void GraphicsFunctionModelGroup::addItem(GraphicsFunctionModelItem* item) { item->setParentItem(this); // 关键:设置父项 diff --git a/diagramCavas/source/graphicsItem/pluginSvgItemWrapper.cpp b/diagramCavas/source/graphicsItem/pluginSvgItemWrapper.cpp index 0435cf7..c03f14c 100644 --- a/diagramCavas/source/graphicsItem/pluginSvgItemWrapper.cpp +++ b/diagramCavas/source/graphicsItem/pluginSvgItemWrapper.cpp @@ -31,6 +31,29 @@ PluginSvgItemWrapper::PluginSvgItemWrapper(ICanvasItem *pluginItem, QGraphicsIte qDebug() << "PluginItemWrapper created for:" << m_pluginItem->typeId(); } +PluginSvgItemWrapper::PluginSvgItemWrapper(ICanvasItem *pluginItem,const PluginSvgItemWrapper& obj) + :ElectricFunctionModelSvgItem(obj) + , m_pluginItem(pluginItem) +{ + if (!m_pluginItem) { + qWarning() << "PluginItemWrapper: pluginItem is null!"; + return; + } + // 设置类型 + m_Itemtype = GIT_PluginItem; + + // 设置初始名称 + setName(m_pluginItem->displayName()); + + // 连接信号 + connectSignals(); + + // 更新坐标 + updateCoordinate(); + + qDebug() << "PluginItemWrapper created for:" << m_pluginItem->typeId(); +} + PluginSvgItemWrapper::~PluginSvgItemWrapper() { // 删除插件项 @@ -109,7 +132,7 @@ ElectricFunctionModelSvgItem* PluginSvgItemWrapper::clone() const } // 创建新的包装器 - PluginSvgItemWrapper *clone = new PluginSvgItemWrapper(newPluginItem, parentItem()); + PluginSvgItemWrapper *clone = new PluginSvgItemWrapper(newPluginItem, *this); // 复制变换属性 clone->setPos(pos()); @@ -411,8 +434,8 @@ void PluginSvgItemWrapper::copyPropertiesFrom(const PluginSvgItemWrapper *source // 复制自定义数据 setData(0, source->data(0)); - // 生成新的ID - setItemId(QUuid::createUuid()); + // 复制id + setItemId(source->itemId()); } void PluginSvgItemWrapper::onPluginPropertyChanged(const QString &key, const QVariant &value) diff --git a/diagramCavas/source/monitorPanel.cpp b/diagramCavas/source/monitorPanel.cpp index 816375c..55ad1e6 100644 --- a/diagramCavas/source/monitorPanel.cpp +++ b/diagramCavas/source/monitorPanel.cpp @@ -24,6 +24,7 @@ #include "projectModelManager.h" #include "diagramCavas.h" #include "extraPropertyManager.h" +#include "designerView.h" MonitorPanel::MonitorPanel(PowerEntity* pEntity,QWidget *parent,DiagramMode mode) : BaseDrawingPanel(pEntity,parent,mode) @@ -63,6 +64,29 @@ void MonitorPanel::closeEvent(QCloseEvent *closeEvent) emit panelDelete(_name,2); } +QGraphicsItem* MonitorPanel::findCentralItem() { + QList items = getScene()->items(); + if (items.isEmpty()) return nullptr; + + // 场景中心 + QPointF sceneCenter = getScene()->sceneRect().center(); + + QGraphicsItem* centralItem = nullptr; + qreal minDistance = std::numeric_limits::max(); + + foreach(QGraphicsItem* item, items) { + QPointF itemCenter = item->sceneBoundingRect().center(); + qreal distance = QLineF(sceneCenter, itemCenter).length(); + + if (distance < minDistance) { + minDistance = distance; + centralItem = item; + } + } + + return centralItem; +} + void MonitorPanel::createToolBar() { _toolBar = new QToolBar(this); @@ -547,6 +571,7 @@ void MonitorPanel::loadNodes(QJsonObject obj) } emit _pModel->updateTopologyItems(lstFirst, true,true); + _pModel->setBayHierachy(lstFirst); // 第二阶段:处理所有设备 QList lstSecond; @@ -607,6 +632,7 @@ void MonitorPanel::loadNodes(QJsonObject obj) } emit _pModel->updateTopologyItems(lstSecond, false,true); + _pModel->setItemHierachy(lstSecond); QList lstRef = DataBase::GetInstance()->getHMIRefAll(QUuid(_pEntity->id())); _pModel->getHMIimageRef() = lstRef; @@ -632,6 +658,10 @@ void MonitorPanel::loadNodes(QJsonObject obj) _pModel->updateModelIcon("",model,svgMap); //更新全部 //***暂没有判断基模名称 } } + + auto pCenter = findCentralItem(); + if(pCenter) + getView()->centerOn(pCenter); } void MonitorPanel::saveNodes(int pageId) @@ -882,6 +912,14 @@ void MonitorPanel::initDisplayState() mapState.insert(16,lst_transformer3w); } +void MonitorPanel::setToobarlVisible(bool b) +{ + if(b) + _toolBar->setVisible(true); + else + _toolBar->setVisible(false); +} + void MonitorPanel::initDisplaySetting() { auto stateMap = _pModel->getMonitorStateMap(); diff --git a/diagramCavas/source/util/baseSelector.cpp b/diagramCavas/source/util/baseSelector.cpp index 7730b7c..bd75119 100644 --- a/diagramCavas/source/util/baseSelector.cpp +++ b/diagramCavas/source/util/baseSelector.cpp @@ -709,6 +709,46 @@ void BaseSelector::setCursor(DesignerScene *scene, const QCursor &cursor) view->setCursor(cursor); } +/*void BaseSelector::updateConnectLineByTopology(QList lst) +{ + for(auto iter:lst) //更新连接线 + { + auto item = dynamic_cast(iter); + if(item) + { + if(item->getItemType() != GIT_link) //获取非电缆对象 + { + QUuid nId = item->itemId(); + auto lstConnect = TopologyManager::instance().getConnectionsFor(nId.toString()); + for(auto &pConnect:lstConnect) + { + if(pConnect) + { + QString fromTerminalId = pConnect->fromTerminalId(); //connect自身包含头尾巴顺序 + QString toTerminalId = pConnect->toTerminalId(); + + QPointF fromPos = _model->getTerminalPos(fromTerminalId); + QPointF toPos = _model->getTerminalPos(toTerminalId); + + QRectF itemRect = item->boundingRect(); + QPointF itemPos = item->scenePos(); + + ElectricFunctionModelConnectLineItem* connectItem = _model->getLineItemById(fromTerminalId); + if(connectItem) + { + connectItem->setStartPoint(fromPos); + connectItem->setEndPoint(toPos); + qDebug()<calculatePath(); + } + } + } + } + } + } +}*/ + void BaseSelector::updateConnectLineByTopology(QList lst) { for(auto iter:lst) //更新连接线 @@ -730,12 +770,56 @@ void BaseSelector::updateConnectLineByTopology(QList lst) QPointF fromPos = _model->getTerminalPos(fromTerminalId); QPointF toPos = _model->getTerminalPos(toTerminalId); + // 获取item的位置和大小 + QRectF itemRect = item->boundingRect(); + QPointF itemPos = item->scenePos(); + + // 正确计算item在场景中的矩形 + QRectF itemSceneRect(itemPos.x() + itemRect.x(), + itemPos.y() + itemRect.y(), + itemRect.width(), + itemRect.height()); + + qDebug() << "处理连接线:"; + qDebug() << "fromPos:" << fromPos << "toPos:" << toPos; + qDebug() << "itemRect(局部):" << itemRect; + qDebug() << "itemPos(场景):" << itemPos; + qDebug() << "itemSceneRect:" << itemSceneRect; + + // 定义固定的偏移距离 + const qint32 fixedOffset = 20; // 可以根据需要调整这个值 + + // 检查点是否有有效值(非0,0) + bool fromValid = !(fromPos.isNull() || (fromPos.x() == 0 && fromPos.y() == 0)); + bool toValid = !(toPos.isNull() || (toPos.x() == 0 && toPos.y() == 0)); + + if(fromValid && !toValid) + { + // fromPos有效,toPos无效 + qDebug() << "fromPos有效,toPos无效"; + toPos = calculateMissingPointByKnownPoint(fromPos, itemSceneRect, fixedOffset, false); + } + else if(!fromValid && toValid) + { + // toPos有效,fromPos无效 + qDebug() << "toPos有效,fromPos无效"; + fromPos = calculateMissingPointByKnownPoint(toPos, itemSceneRect, fixedOffset, true); + } + else if(!fromValid && !toValid) + { + // 两个点都无效,使用默认位置 + qDebug() << "两个点都无效"; + fromPos = QPointF(itemSceneRect.left() - fixedOffset, itemSceneRect.center().y()); + toPos = QPointF(itemSceneRect.right() + fixedOffset, itemSceneRect.center().y()); + } + + qDebug() << "最终: fromPos:" << fromPos << "toPos:" << toPos; + ElectricFunctionModelConnectLineItem* connectItem = _model->getLineItemById(fromTerminalId); if(connectItem) { connectItem->setStartPoint(fromPos); connectItem->setEndPoint(toPos); - //qDebug()<calculatePath(); } } @@ -745,3 +829,54 @@ void BaseSelector::updateConnectLineByTopology(QList lst) } } +QPointF BaseSelector::calculateMissingPointByKnownPoint(const QPointF& knownPoint, + const QRectF& itemSceneRect, + qint32 offset, + bool isFromPoint) +{ + QPointF missingPoint; + QPointF itemCenter = itemSceneRect.center(); + + // 计算相对中心的位置 + qreal dx = knownPoint.x() - itemCenter.x(); + qreal dy = knownPoint.y() - itemCenter.y(); + + qDebug() << "相对中心: dx=" << dx << "dy=" << dy; + + // 判断主要方向 + if(qAbs(dx) > qAbs(dy)) + { + // 主要是水平方向 + if(dx > 0) + { + // 在中心右侧 → 放在更右侧 + missingPoint = QPointF(itemSceneRect.right() + offset, knownPoint.y()); + qDebug() << "右侧 → 更右侧"; + } + else + { + // 在中心左侧 → 放在更左侧 + missingPoint = QPointF(itemSceneRect.left() - offset, knownPoint.y()); + qDebug() << "左侧 → 更左侧"; + } + } + else + { + // 主要是垂直方向 + if(dy > 0) + { + // 在中心下方 → 放在更下方 + missingPoint = QPointF(knownPoint.x(), itemSceneRect.bottom() + offset); + qDebug() << "下方 → 更下方"; + } + else + { + // 在中心上方 → 放在更上方 + missingPoint = QPointF(knownPoint.x(), itemSceneRect.top() - offset); + qDebug() << "上方 → 更上方"; + } + } + + qDebug() << "计算出的缺失点:" << missingPoint; + return missingPoint; +} diff --git a/diagramCavas/ui/customHMIGenerateDlg.ui b/diagramCavas/ui/customHMIGenerateDlg.ui index d483838..7dffce9 100644 --- a/diagramCavas/ui/customHMIGenerateDlg.ui +++ b/diagramCavas/ui/customHMIGenerateDlg.ui @@ -267,6 +267,13 @@ QWidget QLabel { + + + + + + +