Qt 遍历不规则树的节点
阅读原文时间:2023年07月10日阅读:4

在使用Qt的GraphicsScene作图时,遇到类似这样的需求:在scene中创建节点类似下图,

现在我要把每个节点的txt保存到xml文件中,结构为


并且,还要能根据xml文件将这个结构还原出来(由于没有保存坐标信息,当然不能恢复原状)。

我将过程分为:遍历,保存xml;读取xml,还原图形。

我使用Qt的示例项目DiagramScene来改造。

首先,起始节点要与其他节点有所不同,便于我们区分。diagramitem类中,DiagramType { Step, Conditional, StartEnd, Io };,我添加一个virStep类型作为开始节点,其他节点类型为Step。其实virStep和Step的图形一模一样,只是类型不同。

在DiagramItem类中增加一些成员

QList getArrow(){return arrows;}

void setText(QString text){ mText = text;}

void setItemId(QString pid){ ItemId = pid;}//唯一标识,在创建时设置

QString getItemId(){return ItemId;}

QString getText(){ return mText; }
重写其paint函数,在其中添加:

painter->drawText(boundingRect() , Qt::AlignCenter ,mText);

保存:

bool OperateItemFile::SaveRelationship(QList &listItem, QList &listArrow)
{
QFileDialog dlg;
dlg.setAcceptMode(QFileDialog::AcceptSave);
QString strName = dlg.getSaveFileName(getMainWindow() ,QObject::tr("save xml file"), "" ,QObject::tr("XML文件(*.XML)"));
if(strName.isEmpty())
return false;

QDomDocument doc;  
doc.appendChild( doc.createProcessingInstruction("xml", XML\_HEAD\_INFO));  
QFile file(strName);  
if (!file.open(QIODevice::WriteOnly)){  
    return false;  
}  
QDomElement root = doc.createElement("Root");  
doc.appendChild(root);

DiagramItem\* startItem = NULL ;  
QDomElement startEle;  
for (int i = 0; i < listItem.size(); i++) {  
    if(listItem.at(i)->diagramType() == DiagramItem::virStep){  
        //开始节点  
        startEle = doc.createElement(listItem.at(i)->getText());  
        root.appendChild(startEle);  
        startItem = listItem.at(i);  
        //listItem.removeAt(i);  
        break;  
    }  
}

if(!startItem) return false;

TravelAllItem(startItem, doc, startEle, listItem);

QString xml = doc.toString();  
QTextStream txtOutput(&file);  
txtOutput.setCodec("UTF-8");  
txtOutput<<xml;  
file.close();

return true;  

}

void OperateItemFile::GetSubItems(DiagramItem *item, QList& listNodeItem)
{
if(!item) return;

listNodeItem.clear();  
QList<Arrow\*> listArrow = item->getArrow();  
for (int i = 0; i < listArrow.size(); i++) {  
    if(listArrow.at(i)->startItem() == item){  
        listNodeItem.push\_back(listArrow.at(i)->endItem());  
    }  
}  

}

void OperateItemFile::TravelAllItem(DiagramItem *rootItem, QDomDocument &doc, QDomElement &rootEle, QList &listItem)
{
if(listItem.size() < 1) return; QList listNodeItem;
GetSubItems(rootItem, listNodeItem);
for (int i = 0; i < listNodeItem.size(); i++) { QDomElement ele = doc.createElement(listNodeItem.at(i)->getText());
rootEle.appendChild(ele);
listItem.removeOne(rootItem);
TravelAllItem(listNodeItem.at(i), doc, ele, listItem);

}

}

使用GraphicsScene的selectItems函数,从中分别获得diagramitem和arrow。代码如果编译不通,可根据情况修改。

读入xml:

void OperateItemFile::ImportTargetFile(DiagramScene* pScene)
{
QString strName;
strName = QFileDialog::getOpenFileName(nullptr, QObject::tr("open xml file"), p_globalObject->ProjectPath() + "/" + p_globalObject->getProjectName() ,QObject::tr("XML文件(*XML*)"));
if(strName.isEmpty()){
return;
}

QDomDocument doc;  
QFile file(strName);  
if (!file.open(QIODevice::ReadOnly)){  
    return ;  
}  
if (!doc.setContent(&file))  
{  
    file.close();  
    return ;  
}

QDomNode domNodeStart = doc.documentElement();  
QList<DiagramItem\*> listItem;  
QList<Arrow\*> listArrow;  
m\_bStartNode = true;  
SetItemPos(pScene->sceneRect().center());  
parsePackage(domNodeStart, listItem, listArrow);

pScene->ItemClear();

int i=0;  
for(i=0 ;i<listItem.size() ;i++){  
    pScene->addItem(listItem.at(i));  
}  
pScene->setMode(DiagramScene::Mode::MoveItem);  
////////////////////////////////////////////////////////////////////////////////////  
//设置箭头起始节点  
int j=0;  
for(i=0 ;i<listArrow.size(); i++){  
    for(j=0 ;j<listItem.size() ;j++){  
        if(listArrow.at(i)->getStartId() == listItem.at(j)->getItemId()){  
            listArrow.at(i)->setStartItem(listItem.at(j));  
            break;  
        }  
    }  
}  
//设置箭头结尾节点  
for(i=0 ;i<listArrow.size(); i++){  
    for(j=0 ;j<listItem.size() ;j++){  
        if(listArrow.at(i)->getEndId() == listItem.at(j)->getItemId()){  
            listArrow.at(i)->setEndItem(listItem.at(j));  
            break;  
        }  
    }  
}

for(i=0 ;i<listArrow.size() ;i++){  
    if(listArrow.at(i)->startItem()!=NULL)  
        listArrow.at(i)->startItem()->addArrow(listArrow.at(i));

    if(listArrow.at(i)->endItem()!=NULL)  
        listArrow.at(i)->endItem()->addArrow(listArrow.at(i));

    listArrow.at(i)->setColor(pScene->lineColor());  
    listArrow.at(i)->setZValue(-1000.0);  
    pScene->addItem(listArrow.at(i));  
    if(p\_globalObject->getCurStatus() == QGlobalObject::devStatus)  
        listArrow.at(i)->setArrowFlag(true);  
    else  
        listArrow.at(i)->setArrowFlag(true);  
    listArrow.at(i)->updatePosition();  
}

file.close();  

}

bool OperateItemFile::parsePackage(QDomNode pNode, QList& listItem, QList& listArrow)
{
QDomNode myNode = pNode.firstChild();
while(!myNode.isNull()){
QDomElement domE = myNode.toElement();
QString qstrTagName = domE.tagName();
myDebug(qstrTagName);
if(qstrTagName.compare(PackageRoot) != 0 && !qstrTagName.isEmpty()) {
DiagramItem* pItem = NULL;
if(m_bStartNode){
pItem = new DiagramItem(DiagramItem::virStep ,NULL);
domE.setAttribute("StartItem", "true");
m_bStartNode = false;
}
else {
pItem = new DiagramItem(DiagramItem::Step ,NULL);
}
pItem->setPos(m_itemPos);
m_itemPos = GetNextItemPos(m_itemPos);
//pItem->setZValue(z.toFloat());
pItem->setBkColor(QColor(4294967295));
pItem->setItemId(p_globalObject->getGUID());
pItem->setText(qstrTagName);
pItem->setBrush(QBrush(4294967295, (Qt::BrushStyle)1));
domE.setAttribute("ItemId", pItem->getItemId());
if(!domE.hasAttribute("StartItem")){
Arrow* pArrow = new Arrow(NULL, NULL);
QString startItemId = pNode.toElement().attribute("ItemId");
QString endItemId = pItem->getItemId();
pArrow->setItemId(startItemId, endItemId);
listArrow.push_back(pArrow);
}
listItem.push_back(pItem);
}

    parsePackage(myNode, listItem, listArrow);

    myNode = myNode.nextSibling();  
}  
return true;  

}

QPointF OperateItemFile::GetNextItemPos(QPointF preItemPos)
{
float rat = 1;
qreal x = preItemPos.x()+80;
qreal y = x*rat;
QPointF pt(x,y);
return pt;
}

先写到这里,下一篇将写一下,如何完全还原图形。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章