#ifndef GRAPHICSBASEITEM_H #define GRAPHICSBASEITEM_H #include "itemControlHandle.h" #include "global.h" #include #include #include #include #include #include #include //#include "graphicsItem/itemPort.h" enum ShapeType { T_undefined, T_item, T_group }; enum ItemState { S_normal = 0, S_prepareConnect, }; //基类采用模板形式,QGraphicsItem是默认值,也可以是别的类型,比如QGraphicsItemGroup,这样不同的基类继承可以共用一些高层的行为定义 template class AbstractShapeType : public BaseType { public: explicit AbstractShapeType(QGraphicsItem *parent = 0) : BaseType(parent) { m_type = T_undefined; m_pen = QPen(Qt::NoPen); m_brush = QBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8)); m_dWidth = m_dHeight = 0; m_pOperationCopy = nullptr; m_dSyncRotationByParent = 0.0; } AbstractShapeType(const AbstractShapeType& obj) { m_type = T_undefined; m_pen = QPen(Qt::NoPen); m_brush = QBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8)); m_dWidth = m_dHeight = 0; m_pOperationCopy = nullptr; m_dSyncRotationByParent = 0.0; m_itemId = obj.m_itemId; m_type = obj.m_type; m_pen = obj.m_pen; m_brush = obj.m_brush; m_dWidth = obj.m_dWidth; m_dHeight = obj.m_dHeight; m_boundingRect = obj.m_boundingRect; m_Itemtype = obj.m_Itemtype; m_movingIniPos = obj.m_movingIniPos; } virtual ~AbstractShapeType() { } public: virtual ShapeType getType() {return m_type;} virtual QUuid itemId() const {return m_itemId;} virtual void setItemId(QUuid n){m_itemId = n;} QPen pen() { return m_pen; } void setPen(const QPen &pen) { m_pen = pen; } QColor penColor() { return m_pen.color(); } void setPenColor(const QColor &color) { m_pen.setColor(color); } QBrush brush() { return m_brush; } void setBrush(const QBrush &brush) { m_brush = brush; } QColor brushColor() { return m_brush.color(); } void setBrushColor(const QColor &color) { m_brush.setColor(color); } double width() { return m_dWidth; } void setWidth(double width) { m_dWidth = width; updateCoordinate(); } double height() { return m_dHeight; } void setHeight(double height) { m_dHeight = height; updateCoordinate(); } //操作副本相关 virtual void createOperationCopy() {} virtual void removeOperationCopy() {} virtual void moveOperationCopy(const QPointF&) {} virtual void rotateOperationCopy(const double&) {} virtual void resize(int,double, double, const QPointF&) {} virtual void move(const QPointF&) {} virtual void editShape(int, const QPointF&) {} virtual void updateCoordinate() {} virtual void setBoundingRect(QRectF rec){m_boundingRect = rec;} virtual QRectF boundingRect() const { return m_boundingRect; } virtual QPainterPath shape() { QPainterPath path; return path; } virtual void syncRotationDataFromParent(const double&) {} virtual double getSyncRotationDataFromParent() {return m_dSyncRotationByParent;} virtual void setItemType(GraphicsItemType type){m_Itemtype = type;} virtual GraphicsItemType getItemType() const {return m_Itemtype;} protected: QUuid m_itemId; ShapeType m_type; QPen m_pen; QBrush m_brush; double m_dWidth; double m_dHeight; QRectF m_boundingRect; GraphicsItemType m_Itemtype; //显示类型 double m_dSyncRotationByParent; //父项(被加入到某一组)的旋转数据,因为加入某一组后,对该组进行旋转,自身的旋转数据不会同步更新 QGraphicsPathItem* m_pOperationCopy; //图元移动和旋转时的操作副本 QPointF m_movingIniPos; //移动副本开始移动初始 }; class ItemPort; class ModelProperty; class PowerEntity; class AbstractProperty; class HandleText; typedef AbstractShapeType AbstractShape; class GraphicsNonStandardItem:public QObject, public AbstractShapeType //非标准图元,如间隔 { Q_OBJECT public: GraphicsNonStandardItem(QGraphicsItem *parent = 0) :AbstractShapeType(parent) { setFlag(QGraphicsItem::ItemIsSelectable, true); } virtual ~GraphicsNonStandardItem(){}; virtual void setProperty(AbstractProperty* p){_property = p;} virtual AbstractProperty* getProperty() {return _property;} bool containsPoint(const QPointF& pos) { QPointF localPos = mapFromScene(pos); QPainterPath path = shape(); // 或更精确的计算 return path.contains(localPos); } protected: AbstractProperty* _property; }; class GraphicsBaseItem :public QObject, public AbstractShapeType { Q_OBJECT public: GraphicsBaseItem(QGraphicsItem *parent); GraphicsBaseItem(const GraphicsBaseItem&); virtual ~GraphicsBaseItem(); virtual GraphicsBaseItem* clone() const = 0; public: virtual int addPort(PortState typ,QPointF vec,QString id = "",HandleType hType = T_lineInOut,PortPos pos = P_top,double dXPercent = 0,double dYPercent = 0); //新建,返回-1失败 virtual void movePort(QString id,QPointF vec); //移动可动点 virtual void setEntity(PowerEntity*); //设置当前图元的拓扑数据 virtual PowerEntity* entity(); virtual void setProperty(ModelProperty* p); virtual ModelProperty* getProperty() {return _property;} virtual void updateByProperty(){}; //使用data对象更新自己 virtual void setItemChanged(bool b){_itemChanged = b;} virtual bool itemChanged() const {return _itemChanged;} virtual void renderSelectBackground(QPainter*); virtual ItemPort* getPortById(QString) const; virtual ItemPort* getPortPtr(int) const; virtual ItemControlHandle* getHandlePtr(int) const; virtual QMap getPorts() {return m_mapPort;} //virtual GraphicsBaseItem* virtual void initialPortsByDatabase(int nComponentTypeId); //从数据库初始化port信息,component_type中的id virtual void setLastPoint(QPointF p) {m_lastPoint = p;} virtual void setTouched(bool b){m_touched = b;} virtual void setPosChanged(bool b){_posChanged = b;} virtual bool getPosChanged() {return _posChanged;} virtual void setMoveable(bool b){_bMove = b;} virtual bool getMoveable(){return _bMove;} virtual void addDynamicText(QString tag,QString para); //动态显示数据 virtual void removeDynamicText(QString tag); //移除动态显示数据 virtual void removeAllDynamicText(); virtual bool hasDynamicText(const QString& tag); virtual void setDynamicLayoutRadius(qreal radius); virtual QMap getDynamicText() {return m_mapDynamicText;} int collidesWithHandle(const QPointF& point) { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if (pHandle) { QPointF pt = pHandle->mapFromScene(point); if(pHandle->contains(pt)) { if(pHandle->enable()) return pHandle->getTag(); } } } return HandleTag::H_none; } //handle相关 virtual int handleCount() { return m_vecHanle.count(); } virtual ItemControlHandle* getHandle(int nHandle) { ItemControlHandle* handle = nullptr; foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if (pHandle) { if(pHandle->getTag() == nHandle) { handle = pHandle; return handle; } } } return handle; } virtual void setHandleVisible(bool bVisible) { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { if(pHandle->ifShow()) { if(bVisible) pHandle->show(); else pHandle->hide(); } } } } virtual void setHandleVisible(int tag,bool bVisible) { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { if(pHandle->getTag() == tag) { if(bVisible) pHandle->show(); else pHandle->hide(); break; } } } } virtual void setHandleIfShow(int tag,bool bVisible) //是否参与显示判断 { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { if(pHandle->getTag() == tag) { pHandle->setIfShow(bVisible); break; } } } } virtual void setFunctionHandleIfShow(bool bVisible) //是否参与显示判断 { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { if(pHandle->getTag() < H_connect) { pHandle->setIfShow(bVisible); } } } } virtual void setFunctionHandleEnaable(bool val) { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { if(pHandle->getTag() < H_connect) //设置port以外端点是否交互 pHandle->setEnable(val); } } } virtual void setHandleEnaable(HandleTag tag,bool val) { foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { if(pHandle->getTag() == tag) //设置端点是否交互 { pHandle->setEnable(val); break; } } } } virtual QPointF getSymmetricPointPos(int nHandle) //获取对称点的坐标位置,缩放的时候需要以对称点为锚点 { QPointF pt; //handle的位置相对boundingRect会有一个向外的错位,因此直接采用bounddingRect的相应位置会更精准 switch (nHandle) { case H_leftTop: //pt = m_vecHanle.at(H_rightBottom - 1)->pos(); pt = m_boundingRect.bottomRight(); break; case H_top: //pt = m_vecHanle.at(H_bottom - 1)->pos(); pt = QPointF(m_boundingRect.width() * 0.5, m_boundingRect.bottom()); break; case H_rightTop: //pt = m_vecHanle.at(H_leftBottom - 1)->pos(); pt = m_boundingRect.bottomLeft(); break; case H_right: //pt = m_vecHanle.at(H_left - 1)->pos(); pt = QPointF(m_boundingRect.left(), m_boundingRect.height() * 0.5); break; case H_rightBottom: //pt = m_vecHanle.at(H_leftTop - 1)->pos(); pt = m_boundingRect.topLeft(); break; case H_bottom: //pt = m_vecHanle.at(H_top - 1)->pos(); pt = QPointF(m_boundingRect.width() * 0.5, m_boundingRect.top()); break; case H_leftBottom: //pt = m_vecHanle.at(H_rightTop - 1)->pos(); pt = m_boundingRect.topRight(); break; case H_left: //pt = m_vecHanle.at(H_right - 1)->pos(); pt = QPointF(m_boundingRect.right(), m_boundingRect.height() * 0.5); break; default: break; } return pt; } virtual void updateHandles() { int nMargin = 5; const QRectF& boundRect = this->boundingRect(); foreach (int key, m_vecHanle.keys()) { ItemControlHandle* pHandle = m_vecHanle.value(key); if(pHandle) { switch (pHandle->getTag()) { case H_leftTop: pHandle->move(boundRect.x() - nMargin, boundRect.y() - nMargin); break; case H_top: pHandle->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() - nMargin); break; case H_rightTop: pHandle->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() - nMargin); break; case H_right: pHandle->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() + boundRect.height() * 0.5 + nMargin); break; case H_rightBottom: pHandle->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() + boundRect.height() + nMargin); break; case H_bottom: pHandle->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() + boundRect.height()+ nMargin); break; case H_leftBottom: pHandle->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() + nMargin); break; case H_left: pHandle->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() * 0.5); break; case H_rotate_leftTop: { ItemControlHandle* handle = getHandle(H_leftTop); if(handle) { int nSize = handle->getSize(); QPointF pt = handle->pos(); pHandle->move(pt.x() - nSize - 1, pt.y() - nSize - 1); } else pHandle->setVisible(false); break; } case H_rotate_rightTop: { ItemControlHandle* handle = getHandle(H_rightTop); if(handle) { int nSize = handle->getSize(); QPointF pt = handle->pos(); pHandle->move(pt.x() + nSize + 1, pt.y() - nSize - 1); } else pHandle->setVisible(false); break; } case H_rotate_rightBottom: { ItemControlHandle* handle = getHandle(H_rightBottom); if(handle) { int nSize = handle->getSize(); QPointF pt = handle->pos(); pHandle->move(pt.x() + nSize + 1, pt.y() + nSize + 1); } else pHandle->setVisible(false); break; } case H_rotate_leftBottom: { ItemControlHandle* handle = getHandle(H_leftBottom); if(handle) { int nSize = handle->getSize(); QPointF pt = handle->pos(); pHandle->move(pt.x() - nSize - 1, pt.y() + nSize + 1); } else pHandle->setVisible(false); break; } default: break; } } } double dWidth = boundRect.width(); double dHeight = boundRect.height(); double dDiagonal = sqrt((dWidth* 0.5)*(dWidth * 0.5)+(dHeight*0.5)*(dHeight*0.5)); double dParam = dWidth > dHeight ? (dDiagonal-dWidth*0.5):(dDiagonal-dHeight*0.5); m_boundingRect_selected = boundRect.adjusted(-dParam-nMargin, -dParam-nMargin, dParam+nMargin, dParam+nMargin); } void rearrangeDynamicItems(); public slots: void onUpdateData(); //data发送的更新通知 protected: void rearrangeDynamicText(); //重新设置动态数据的布局 protected: ModelProperty* _property; PowerEntity* _pEntity; //图元拓扑 bool _itemChanged; //图元变化标志,判断是否需要保存 QMap m_mapPort; //单独存放port QMap m_mapDynamicText; //单独存放动态数据 QMap m_vecHanle; QPointF m_lastPoint; //鼠标上次点击位置 bool m_touched; //被触碰状态 QRectF m_boundingRect_selected; //选中矩形框 bool _posChanged = false; //位置移动标志 bool _bMove = true; //是否允许移动 private: qreal m_layoutRadius; // 布局半径 (动态数据使用) }; class GraphicsBaseModelItem : public GraphicsBaseItem //基模item { Q_OBJECT public: GraphicsBaseModelItem(QGraphicsItem *parent); GraphicsBaseModelItem(const GraphicsBaseModelItem&); virtual ~GraphicsBaseModelItem(); virtual GraphicsBaseModelItem* clone() const override; virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; virtual void setMask(bool b){_stateMask = b;} virtual bool getMask(){return _stateMask;} protected: virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&) override; bool _stateMask = true; //状态遮罩 }; class GraphicsBaseModelGroup : public GraphicsBaseModelItem //基模group { Q_OBJECT public: GraphicsBaseModelGroup(QGraphicsItem *parent); GraphicsBaseModelGroup(const GraphicsBaseModelGroup&); virtual ~GraphicsBaseModelGroup(); virtual GraphicsBaseModelGroup* clone() const override; virtual void addItem(GraphicsBaseModelItem* item); virtual void updateLayout(); virtual QRectF boundingRect() const override; virtual void setLayout(int n) {_layout = n;} protected: QList m_childItems; int _layout = 0; //组内布局,0横1纵 }; class GraphicsProjectModelItem : public GraphicsBaseItem //工程模item { Q_OBJECT public: GraphicsProjectModelItem(QGraphicsItem *parent); GraphicsProjectModelItem(const GraphicsProjectModelItem&); virtual ~GraphicsProjectModelItem(); virtual GraphicsProjectModelItem* clone() const override; virtual void createOperationCopy() override; virtual void removeOperationCopy() override; virtual void moveOperationCopy(const QPointF&) override; virtual void rotateOperationCopy(const double&) override; virtual void syncRotationDataFromParent(const double&) override; //多边形、线段等点选创建的对象需要的函数 virtual void addPoint(const QPointF&) {} virtual bool endDrawing() { return true; } virtual void setLabelTag(const QString& name); //设置名字牌 virtual QString getLabelTag() const; virtual void setLabelCurrent(const QString& str); //设置电流标签 virtual QString getLabelCurrent() const; virtual void setLabelVoltage(const QString& str); //设置电压标签 virtual QString getLabelVoltage() const; //virtual void addPort(PortState typ,int ntagId,QPointF vec); //载入 PortState为P_const时,QPointF中为(0~1,0~1)的相对位置;PortState为p_movable时,QPointF为坐标值 virtual void setState(ItemState s){m_state = s;} virtual void setBeginConnectPos(QPointF p){m_beginConnectPoint = p;} virtual void setEndConnectPos(QPointF p){m_endConnectPoint = p;} virtual void setLastPort(int n){_lastPort = n;} virtual int getLastPort() const {return _lastPort;} virtual void unbindProperty(); //断开图元与数据的绑定 virtual void updateByProperty() override; //使用data对象更新自己 virtual void updateConnectData(); //更新连接关系数据 virtual void setModelName(QString sName){_modelName = sName;} virtual QString getModelName() const {return _modelName;} virtual void setupFinish(QVariant){} //设置完成后调用(如ct,pt) virtual void updateItem(){}; //更新自身(如ct,pt) virtual void updateTerPos(); //ct,pt等item大小变动后重新计算端点位置 virtual void setCurMonitorState(monitorItemState sta) {_curMonitorState = sta;} //设置当前运行时模式 virtual void setMonitorDisplayInfo(QMap info){_displaySetting = info;} protected: virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&) override; virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent*) override; virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; signals: void ifExist(QUuid id,const QString&,int type,GraphicsProjectModelItem*); public slots: void onEditNameFinish(const QString&); protected: ItemState m_state; QPointF m_beginConnectPoint; QPointF m_endConnectPoint; int _lastPort; //最后触碰的port QString _modelName; //当前图元使用的模型名,用来在model中检索属性信息 monitorItemState _curMonitorState; //当前运行时模式 QMap _displaySetting; //显示设置 }; class GraphicsProjectModelGroup : public GraphicsProjectModelItem //工程模group { Q_OBJECT public: GraphicsProjectModelGroup(QGraphicsItem *parent); GraphicsProjectModelGroup(const GraphicsProjectModelGroup&); virtual ~GraphicsProjectModelGroup(); virtual GraphicsProjectModelGroup* clone() const override; virtual void addItem(GraphicsProjectModelItem* item); virtual void updateLayout(); //virtual QRectF boundingRect() const override; virtual void setLayout(int n) {m_direction = n;} virtual void setGroupType(int n) {_groupType = n;} virtual int getGroupType() {return _groupType;} virtual void setSpacing(qreal spacing) { if (m_spacing != spacing) { m_spacing = spacing; updateLayout(); } } QRectF updateBoundRect(); protected: QList m_childItems; int m_direction = 1; //组内布局,0横1纵 int m_spacing = 0; //间距 int _groupType = 0; //组类型,0联合(子item独立连接),1聚合(子item仅作展示) }; #endif