Qt QGraphicsScene绘图节点保存及恢复
在上一篇文章中 Qt 遍历不规则树的节点,介绍了节点保存及恢复,但是恢复时不是将原有节点原样恢复。这里介绍怎样恢复原样。
思路:要恢复恢复,首先肯定要有节点的坐标(在scene中)。节点恢复后,还要使用箭头连接。据此,我们保存时,要保存节点坐标,及箭头首尾节点。根据上一篇文章,我们在创建时已经给节点了唯一标识。
唯一标识代码:
QString getGUID() { QUuid id = QUuid::createUuid(); QString strId = id.toString(); return strId; }
保存函数及说明如下:
bool OperateItemFile::SaveItemArrowFile(QList<DiagramItem *> &pItemList, QList<Arrow *> &pArrowList, QString itFilePath) { if(pItemList.size() > 0){ QDomDocument doc; doc.appendChild( doc.createProcessingInstruction("xml", XML_HEAD_INFO)); QFile file(itFilePath); if (!file.open(QIODevice::WriteOnly)){ return false; } QDomElement root = doc.createElement("Root"); doc.appendChild(root); //设备节点 QDomElement dev = doc.createElement("DeviceVerb"); root.appendChild(dev); for(int i=0 ;i<pItemList.size() ;i++){ QDomElement ItemE = doc.createElement("Device"); ItemE.setAttribute("ItemId" ,pItemList.at(i)->getItemId()); ItemE.setAttribute("left" ,pItemList.at(i)->boundingRect().left()); ItemE.setAttribute("top" ,pItemList.at(i)->boundingRect().top()); ItemE.setAttribute("right" ,pItemList.at(i)->boundingRect().right()); ItemE.setAttribute("bottom" ,pItemList.at(i)->boundingRect().bottom()); ItemE.setAttribute("name" ,pItemList.at(i)->getText()); ItemE.setAttribute("x" ,pItemList.at(i)->pos().x()); ItemE.setAttribute("y" ,pItemList.at(i)->pos().y()); ItemE.setAttribute("z" ,pItemList.at(i)->zValue()); ItemE.setAttribute("color" ,pItemList.at(i)->brush().color().rgb()); ItemE.setAttribute("brushstyle" ,pItemList.at(i)->brush().style()); ItemE.setAttribute("type" ,pItemList.at(i)->diagramType()); getItemChild(pItemList, pItemList.at(i), doc, ItemE); dev.appendChild(ItemE); } //保存箭头 if(pArrowList.size() > 0){ QDomElement arrow = doc.createElement("ArrowVerb"); root.appendChild(arrow); for(int i=0 ;i<pArrowList.size() ;i++){ QDomElement ArrowItem = doc.createElement("Arrow"); ArrowItem.setAttribute("StartItemId" ,pArrowList.at(i)->getStartId()); ArrowItem.setAttribute("EndItemId" ,pArrowList.at(i)->getEndId()); arrow.appendChild(ArrowItem); } } QString xml = doc.toString(); QTextStream txtOutput(&file); txtOutput.setCodec("UTF-8"); txtOutput<<xml; file.close(); } return true; }
函数中的参数依次是:所有节点,所有箭头,及保存的文件名。
恢复函数如下:
bool OperateItemFile::getNormalItem(QString itemType, QList<DiagramItem *> *pList, QDomNodeList &domList, QMenu *itemMenu)
{ for (int i = 0; i < domList.size(); i++) { QStringList szAttrVal; QDomElement fileElem = domList.at(i).toElement(); QString l = fileElem.attribute("left"); QString t = fileElem.attribute("top"); QString r = fileElem.attribute("right"); QString b = fileElem.attribute("bottom"); QString name = fileElem.attribute("name"); QString id = fileElem.attribute("ItemId"); QString x = fileElem.attribute("x"); QString y = fileElem.attribute("y"); QString z = fileElem.attribute("z"); QString type = fileElem.attribute("type"); QString rgb = fileElem.attribute("color"); QString brushstyle = fileElem.attribute("brushstyle"); DiagramItem* pItem = new DiagramItem((DiagramItem::DiagramType)type.toUInt() ,itemMenu); pItem->setPos(QPointF(x.toFloat() ,y.toFloat())); pItem->setZValue(z.toFloat()); pItem->setBkColor(QColor(rgb.toUInt())); pItem->setItemId(id); pItem->setText(name); pItem->setBrush(QBrush(rgb.toUInt(), (Qt::BrushStyle)brushstyle.toUInt())); if(itemType.compare("Port") == 0) { QString parentItemId = fileElem.attribute("parentItemId"); pItem->setParentItemId(parentItemId); } szAttrVal.push_back(name); szAttrVal.push_back(rgb); szAttrVal.push_back("False"); szAttrVal.push_back(""); szAttrVal.push_back(""); szAttrVal.push_back(""); szAttrVal.push_back(""); for (int j = 0; j < szAttrName.size(); j++) { pItem->setItemAttr(j, szAttrName.at(j), szAttrVal.at(j)); } pList->push_back(pItem); } return true; } bool OperateItemFile::GetItemArrowFromFile(QString strItemPath, QList<DiagramItem *> *pItemList, QList<Arrow *> *pArrowList, QMenu *itemMenu)
{ if(strItemPath.length() <= 0 || pItemList == NULL || pArrowList == NULL) return false; QDomDocument doc; QFile file(strItemPath); if (!file.open(QIODevice::ReadOnly)){ return false; } if (!doc.setContent(&file)) { file.close(); return false; } QDomNodeList listNormalItem = doc.elementsByTagName("Device"); QDomNodeList listPortItem = doc.elementsByTagName("Port"); QDomNodeList listArrow = doc.elementsByTagName("Arrow"); getNormalItem("Item", pItemList, listNormalItem, itemMenu); getNormalItem("Port", pItemList, listPortItem, itemMenu); for (int i = 0; i < listArrow.size(); i++) { QDomElement arrowEle = listArrow.at(i).toElement(); QString sid = arrowEle.attribute("StartItemId"); QString eid = arrowEle.attribute("EndItemId"); Arrow* pItem = new Arrow(NULL ,NULL); pItem->setItemId(sid,eid); pArrowList->push_back(pItem); } file.close(); return true; } bool OperateItemFile::loadItemToScene(DiagramScene* pScene, bool bIsDialog, QString srcPath)
{ if(!pScene) return false; QList<DiagramItem*> itemList; QList<Arrow*> ArrowList; QString strName; if(bIsDialog) strName = QFileDialog::getOpenFileName(nullptr, QObject::tr("open xml file"), p_globalObject->ProjectPath() + "/" + p_globalObject->getProjectName() ,QObject::tr("XML文件(*XML*)")); else strName = srcPath; //////////////////////////////////////////////////////////////////////////////////// if(!GetItemArrowFromFile(srcPath, &itemList, &ArrowList, NULL)) return false; pScene->ItemClear(); int i=0; for(i=0 ;i<itemList.size() ;i++){ //itemList.at(i)->setBrush(pScene->itemColor()); pScene->addItem(itemList.at(i)); } pScene->setMode(DiagramScene::Mode::MoveItem); //设置箭头起始节点 int j=0; for(i=0 ;i<ArrowList.size(); i++){ for(j=0 ;j<itemList.size() ;j++){ if(ArrowList.at(i)->getStartId() == itemList.at(j)->getItemId()){ ArrowList.at(i)->setStartItem(itemList.at(j)); break; } } } //设置箭头结尾节点 for(i=0 ;i<ArrowList.size(); i++){ for(j=0 ;j<itemList.size() ;j++){ if(ArrowList.at(i)->getEndId() == itemList.at(j)->getItemId()){ ArrowList.at(i)->setEndItem(itemList.at(j)); break; } } } for(i=0 ;i<ArrowList.size() ;i++){ if(ArrowList.at(i)->startItem()!=NULL) ArrowList.at(i)->startItem()->addArrow(ArrowList.at(i)); if(ArrowList.at(i)->endItem()!=NULL) ArrowList.at(i)->endItem()->addArrow(ArrowList.at(i)); ArrowList.at(i)->setColor(pScene->lineColor()); ArrowList.at(i)->setZValue(-1000.0); pScene->addItem(ArrowList.at(i)); if(p_globalObject->getCurStatus() == QGlobalObject::devStatus) ArrowList.at(i)->setArrowFlag(true); else ArrowList.at(i)->setArrowFlag(true); ArrowList.at(i)->updatePosition(); } return true; }
getNormalItem函数中的type,区分是不是子节点。loadItemToScene 的参数bIsDialog,来确定是否显示文件对话框。