add custom HMI generate logic

This commit is contained in:
baiYue 2026-04-28 17:55:57 +08:00
parent 8b5be362ae
commit 80cfa5e815
26 changed files with 615 additions and 59 deletions

View File

@ -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:

View File

@ -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

View File

@ -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<HierarchyItem>);
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<HierarchyItem> _tempLst;
QTimer* m_timer = nullptr;
};
#endif

View File

@ -39,6 +39,7 @@ private:
QStandardItemModel* _modelAll; //图中所有item
// 存储间隔名称到树节点的映射,提高查找效率
QHash<QString, QStandardItem*> m_mapBayItems;
bool m_isProgrammaticChange = false; //程序设置标志
};
#endif

View File

@ -115,7 +115,7 @@ public slots:
void updateHMIlstFromDB(); //从数据库更新HMI列表
//QMap<QString,QPair<MonitorPanel*,QMdiSubWindow*>> getMapMonitor() {return m_mapMonitorPanel;}
QMdiSubWindow* getSubWindow(const QString&);
void onTargetSelected(QObject*); //选中事件(属性显示)
protected:

View File

@ -49,7 +49,7 @@ public:
PluginItemFactory* m_itemFactory = nullptr;
QMap<QString, PluginTypeInfo> 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(); // 显示属性页

View File

@ -111,6 +111,9 @@ public:
QMap<QUuid,QString>& getMonitorParaRef(){return m_monitorParaRef;}
void setMonitorRelation(QList<HierarchyItem> lst){m_lstMonitorRelation = lst;}
QList<HierarchyItem> getMonitorRelation() {return m_lstMonitorRelation;}
void setBayHierachy(QList<HierarchyItem> lst) {m_bayHierachy = lst;}
void setItemHierachy(QList<HierarchyItem> lst) {m_itemHierachy = lst;}
void activePanelHierachy(); //激活当前界面的层级关系
void monitorItemSelected(QUuid); //运行时item选中事件
void monitorItemDetailAttr(QUuid); //显示属性详情
@ -127,6 +130,7 @@ public:
QMap<MonitorItemTypeStruct,QMap<MonitorItemStateStruct,MonitorItemDisplayInfo>>& getMonitorDisplaySetting(){return m_monitorDisplaySetting;}
void previewHMI(SelectPanel* pPreview,QList<HierarchyItem>); //customHMI 生成预览
void customGenerateHMI(QString,QPair<int,int>,QList<HierarchyItem>); //自定义生成HMI
QList<HMIImageRef>& getHMIimageRef(){return _HMIimageRef;}
QList<HMICustomImageRef>& getHMICustomImageRef(){return _HMICustomImageRef;}
int imageRefExist(QString model,QByteArray hash256);
@ -207,7 +211,9 @@ private:
QMap<QUuid,QString> m_monitorParaRef; //监控参数的引用关系(文字item等) <itemId,connectPara>
QMap<int,QList<QPair<MonitorItemState,QString>>> m_monitorStateMap; //元件状态对照表 <type,<state,状态名>>
QMap<MonitorItemTypeStruct,QMap<MonitorItemStateStruct,MonitorItemDisplayInfo>> m_monitorDisplaySetting; //元件设置
QList<HierarchyItem> m_lstMonitorRelation; //监控item层级关系
QList<HierarchyItem> m_lstMonitorRelation; //监控item层级关系(暂无使用)
QList<HierarchyItem> m_bayHierachy; //间隔层级信息
QList<HierarchyItem> m_itemHierachy; //元件层级信息
ItemPropertyDlg* m_curPropertyDlg;
QTimer* m_dataTimer; //获取数据的定时器

View File

@ -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;}

View File

@ -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;

View File

@ -37,6 +37,7 @@ public:
void initDisplaySetting(); //初始化显示状态设置
MonitorConfigDlg* getMonitorConfigDlg() {return _pConfigDlg;}
void setToobarlVisible(bool); //设置运行模式
public:
//对层级关系的序列化与反序列化
QJsonArray serializeRelationToJsonArray(const QList<HierarchyItem>& data) const;
@ -61,6 +62,7 @@ protected:
void closeEvent(QCloseEvent *closeEvent) override;
private:
void createToolBar();
QGraphicsItem* findCentralItem();
private:
QString _sParentPage; //派生自哪个工程
QToolBar* _toolBar;

View File

@ -70,6 +70,8 @@ public:
FixedPortsModel* getModel() {return _model;}
void updateConnectLineByTopology(QList<QGraphicsItem *>); //通过拓扑关系更新位置
// 辅助函数:根据已知点计算缺失点的位置
QPointF calculateMissingPointByKnownPoint(const QPointF& knownPoint, const QRectF& itemSceneRect, qint32 offset, bool isFromPoint);
signals:
void setWorkingSelector(SelectorType);
protected:

View File

@ -83,6 +83,56 @@ BasePannelPropertyProxy* BaseDrawingPanel::getPropertyProxy()
return _pPropertyProxy.data();
}
void BaseDrawingPanel::moveItemsAlignment(Qt::Alignment alignment,const QMarginsF& margins)
{
QList<QGraphicsItem*> 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)

View File

@ -2,6 +2,8 @@
#include "common/frontend/monitor_item.h"
#include "dataBase.h"
#include "ui_createHMIdlg.h"
#include "diagramCavas_p.h"
#include <QTimer>
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);
}

View File

@ -5,6 +5,7 @@
#include "diagramCavas.h"
#include "customHMIList.h"
#include "ui_customHMIGenerateDlg.h"
#include "diagramCavas_p.h"
#include <QVBoxLayout>
CustomHMIGenerateDlg::CustomHMIGenerateDlg(QWidget *parent)
@ -17,6 +18,7 @@ CustomHMIGenerateDlg::CustomHMIGenerateDlg(QWidget *parent)
,_pItemList(nullptr)
{
ui->setupUi(this);
setWindowModality(Qt::ApplicationModal);
_pCanvas = dynamic_cast<DiagramCavas*>(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<HierarchyItem> 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);
}

View File

@ -56,6 +56,10 @@ void CustomHMIList::onUpdateItems(QList<HierarchyItem> 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<HierarchyItem> lst,bool refresh)
void CustomHMIList::onSelectItems(QList<HierarchyItem> 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<HierarchyItem> 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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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<MonitorPanel*>(_widget);
@ -2776,8 +2782,97 @@ void FixedPortsModel::previewHMI(SelectPanel* pPanel,QList<HierarchyItem> 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<int,int> size,QList<HierarchyItem> 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<HierarchyItem> lstFirst;
QList<HierarchyItem> 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<BayProperty*>(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<BaseProperty*>(pItem->getProperty());
if(pPro){
auto pNewItem = pItem->clone();
if(pPro->type() == 8){
auto pLine = dynamic_cast<ElectricFunctionModelConnectLineItem*>(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());
}
}
}

View File

@ -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);

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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); // 关键:设置父项

View File

@ -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)

View File

@ -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<QGraphicsItem*> items = getScene()->items();
if (items.isEmpty()) return nullptr;
// 场景中心
QPointF sceneCenter = getScene()->sceneRect().center();
QGraphicsItem* centralItem = nullptr;
qreal minDistance = std::numeric_limits<qreal>::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<HierarchyItem> lstSecond;
@ -607,6 +632,7 @@ void MonitorPanel::loadNodes(QJsonObject obj)
}
emit _pModel->updateTopologyItems(lstSecond, false,true);
_pModel->setItemHierachy(lstSecond);
QList<HMIImageRef> 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();

View File

@ -709,6 +709,46 @@ void BaseSelector::setCursor(DesignerScene *scene, const QCursor &cursor)
view->setCursor(cursor);
}
/*void BaseSelector::updateConnectLineByTopology(QList<QGraphicsItem *> lst)
{
for(auto iter:lst) //更新连接线
{
auto item = dynamic_cast<GraphicsProjectModelItem*>(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()<<nId<<"start:"<<fromPos.x()<<","<<fromPos.y()<<"end:"<<toPos.x()<<","<<toPos.y();
qDebug()<<itemRect<<","<<itemPos;
connectItem->calculatePath();
}
}
}
}
}
}
}*/
void BaseSelector::updateConnectLineByTopology(QList<QGraphicsItem *> lst)
{
for(auto iter:lst) //更新连接线
@ -730,12 +770,56 @@ void BaseSelector::updateConnectLineByTopology(QList<QGraphicsItem *> 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()<<nId<<"start:"<<fromPos.x()<<","<<fromPos.y()<<"end:"<<toPos.x()<<","<<toPos.y();
connectItem->calculatePath();
}
}
@ -745,3 +829,54 @@ void BaseSelector::updateConnectLineByTopology(QList<QGraphicsItem *> 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;
}

View File

@ -267,6 +267,13 @@ QWidget QLabel {
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_info">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>